golang go immutability mutability

golang - ¿Qué tipos son mutables e inmutables en Google Go Language?



go vs python (6)

En Google Go, leí que las cadenas son inmutables, ¿ok pero son int? ¿Qué pasa con otros tipos? Como un programador ligeramente mayor, prefiero la mutabilidad, aunque conozco los beneficios de la inmutabilidad, prefiero vivir peligrosamente.

Saber qué tipos son mutables o inmutables sería muy útil.

Actualización, lo que más me preocupa son los problemas prácticos que dependen de que el tipo sea mutable o inmutable. Como en el ejemplo típico en Java, si crea una Cadena en un bucle y bucle por 10,000 veces, obtendrá 10,000 Cadenas creadas que luego se recolectarán como basura. Esto realmente ha sido un problema serio en un proyecto en una empresa en la que trabajé.

La pregunta es: ¿la inmutabilidad de Go en algunos casos causa el mismo problema?

Afecta cómo debes tratar la var. (o supongo que lo hace).

Actualización de nuevo, también estoy preocupado por otras preocupaciones prácticas. Saber que algo es inmutable significa que puedo escribir código que es paralelo y las actualizaciones de una referencia del objeto no deberían actualizar las otras referencias. Sin embargo a veces deseo hacer cosas peligrosas, quiero mutabilidad.

Estas son consecuencias de la mutabilidad frente a la inmutabilidad y afectan la forma en que puedo escribir el código.


En mi opinión, primero se deben separar los siguientes dos conceptos:

  • enteros como objetos matemáticos (es decir, valores)

  • variables de tipo int

Entonces la respuesta es: las variables enteras son mutables, los valores enteros son inmutables.

Esta vista es consistente con la especificación Go que establece que las cadenas son inmutables. Obviamente, una variable de cadena es mutable.

Las variables (como concepto) en Go son al menos:

  • variables nombradas (tales como: var i int )
  • variables accesibles a través de punteros

Objetos Go mutable:

  • matrices y rebanadas
  • mapas
  • canales
  • Cierres que capturan al menos 1 variable del alcance externo

Objetos ir inmutables:

  • interfaces
  • booleanos, valores numéricos (incluyendo valores de tipo int )
  • instrumentos de cuerda
  • punteros
  • Punteros de función y cierres que pueden reducirse a punteros de función
  • estructuras que tienen un solo campo

Ir a objetos que algunas personas pueden considerar mutables, mientras que otras personas pueden considerarlos inmutables:

  • estructuras que tienen múltiples campos

Esto me está dando la misma dirección cada vez, así que tal vez las intenciones sean mutables.

package main import "fmt" func main() { var i int i = 5 fmt.Println(&i) i = 6 fmt.Println(&i) var k = 7 i = k fmt.Println(&i) }


La "mutabilidad" solo tiene sentido cuando se habla de algún tipo compuesto, algo que tiene partes "internas", que quizás se pueda cambiar independientemente de la cosa que lo contiene. Las cadenas están compuestas naturalmente de caracteres, y no hay ningún mecanismo en el lenguaje que nos permita cambiar un carácter en una cadena existente, a menos que se asigne una cadena completamente nueva, por lo que decimos que es inmutable.

Para un int, realmente no tiene sentido hablar de mutabilidad, porque ¿cuáles son los "componentes" de un int? Cambia un int asignando un int completamente nuevo, pero la asignación no cuenta como "mutación".

Existe alguna conexión entre los problemas de mutabilidad y los tipos de referencia vs. valor. Semánticamente, no hay diferencia entre un tipo de referencia inmutable y un tipo de valor. ¿Por qué? Supongamos que int era en realidad un puntero a un objeto inmutable (es decir, *InternalIntObject sin funciones para cambiar InternalIntObject ). Una vez que asigne dicho puntero a una variable, siempre representará el mismo valor entero (no puede ser cambiado por otros que comparten el mismo objeto) ya que el objeto es inmutable. Este es el mismo comportamiento que un tipo de valor entero. Puede asignar entradas por operador de asignación; Del mismo modo, puede asignar estos punteros por asignación; el resultado sería el mismo: la variable asignada representa el mismo número entero al que fue asignado. La única diferencia sería la comparación y los operadores aritméticos tendrían que redefinirse para desviar la referencia del puntero para calcular el resultado.

Por lo tanto, la mutabilidad solo es significativa para los tipos de referencia.

En cuanto a lo que pidió, generalmente se considera que los tipos "mutables" son los tipos de referencia excepto la cadena: mapas, canales, segmentos (con respecto a los datos apuntados por el sector) y también punteros a cualquier cosa (ya que puede mutar el valor en la ubicación señalada por el puntero).


No te preocupes, Go te permitirá dispararte en el pie si realmente quieres :-)

Ir no es como Erlang, que podría ser lo que estás tratando con la pregunta.

x := 1 x = 2

asigna una variable, x , con un valor de 1 , luego la reasigna a 2 ; aquí no se asigna memoria adicional.

Como se nota, las cadenas son inmutables, por lo que hacer una manipulación de cadenas puede resultar en hacer copias. Si descubre que desea realizar modificaciones in situ en los datos de caracteres, es probable que desee operar con variables de []byte través del paquete de bytes .

La publicación de Russ Cox sobre esto debería responder a la mayoría de sus preguntas sobre estructuras de datos básicas: http://research.swtch.com/2009/11/go-data-structures.html

Como señalaron otros comentaristas, querrá ver la semántica de los valores de las funciones de Go, ya que pueden ser un poco sorprendentes al principio.

Si tienes la siguiente función:

func (t MyType) myFunc() { // do something to set a field in t }

y llamas tu codigo

myVar.myFunc()

es posible que se sorprenda al ver que esto no hace lo que quiere porque la t que se ve en myFunc() es realmente una copia de myVar .

Pero, lo siguiente funcionará:

func (t *myType) myFunc() { // do something to set a field in t }

porque la función tiene una copia del puntero y puede acceder a la estructura subyacente a través de ese puntero.


Sí, la palabra inmutable aparece exactamente una vez en la especificación Go. Y eso es cuando se habla de type string . Creo que deberías verlo más desde los puntos de vista dual de Assignability y Addressability . Por ejemplo, Go le prohibirá volver a vincular la variable a un valor diferente de un tipo con propiedades no exportadas, obviamente. Algo así como en C ++ para las clases que no proporcionan constructor de copias, pero en Go Pimpl siente mucho menos incómodo, acorde con la participación de los goroutines al comunicar la filosofía.


Su preocupación parece ser más sobre la asignación que la inmutabilidad. La inmutabilidad ciertamente afecta la asignación al hacer que sea imposible reutilizar la memoria. Un compilador inteligente podría posiblemente reutilizar cualquier memoria "inmutable" cuya dirección sepa que no se escape.

Aparte de las cadenas, tenga cuidado con las interfaces. Cualquier cosa más grande que el tamaño de palabra deberá asignarse cuando se asigne a la interfaz (aparte de las optimizaciones). Además, las variables declaradas en un cuerpo de bucle cuyas direcciones se escapan, incluso a través de un cierre, deberán asignarse cada vez a través del bucle. De lo contrario, sin embargo, una asignación es sólo una asignación. El valor simplemente se copia en la memoria representada por la variable.

Si usa make o new en un bucle, o cualquier literal que produzca una referencia, la asignación tendrá que suceder (nuevamente, sujeto a optimización).

Básicamente, todo se reduce a tratar de reutilizar la memoria donde puede, y esperar que el compilador lo haga por usted cuando no pueda, si tiene sentido hacerlo.