Вопрос

In Google Go, I read that Strings are immutable, ok but are int's? What about other types? As a slightly older programmer I prefer mutability even though I know the benefits of immutability, I prefer to live dangerously.

Know what types are mutable or immutable would be very helpful.


Update, what I am mostly concerned about is the practical issues depending upon the type being mutable or immutable. As in the typical example in Java, if you create a String in a loop and loop for 10,000 times, you will get 10,000 String's created which are then later garbage collected. This has actually been a serious issue in a project in a company I worked at.

The the question is, does Go's Immutability in some cases cause the same problem?

It affects how you should treat the var. (or I assume it does).


Update again, I am also concerned about other practical concerns. Knowing that something is immutable means that I can write code which is parallel and updates to one reference of the object should not update the other references. However sometimes I wish to do dangerous things, I want mutability.

These are consequences of mutability vs immutability and affect how I can write the code.

Это было полезно?

Решение

Don't worry -- Go will let you shoot yourself in the foot if you really want to :-)

Go is not like Erlang, which might be what you are getting at with the question.

x := 1
x = 2

allocates one variable, x, with a value of 1, then reassigns it to 2 -- no additional memory is allocated here.

As you note, strings are immutable, so doing a string manipulation can result in making copies. If you find that you want to do in-place modifications to character data, you'll probably want to operate on variables of []byte via the bytes package.

Russ Cox's post about this should answer most of your questions about basic data structures: http://research.swtch.com/2009/11/go-data-structures.html

As other commenters noted, you'll want to look at the value semantics of Go functions -- they might be a little surprising at first.

If you have the following function:

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

and you call in your code

myVar.myFunc()

you might be surprised to see that this doesn't do what you want because the t that is seen in myFunc() is really a copy of myVar.

But, the following will work:

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

because the function has a copy of the pointer and can access the underlying structure via that pointer.

Другие советы

In my opinion, one should first separate the following two concepts:

  • integers as mathematical objects (that is: values)

  • variables of type int

Then the answer is: Integer variables are mutable, integer values are immutable.

This view is consistent with the Go specification which states that strings are immutable. Obviously, a string variable is mutable.

Variables (as a concept) in Go are at least:

  • named variables (such as: var i int)
  • variables accessible via pointers

Mutable Go objects:

  • arrays and slices
  • maps
  • channels
  • closures which are capturing at least 1 variable from the outer scope

Immutable Go objects:

  • interfaces
  • booleans, numeric values (including values of type int)
  • strings
  • pointers
  • function pointers, and closures which can be reduced to function pointers
  • structs having a single field

Go objects which some people may consider mutable, while other people may consider them immutable:

  • structs having multiple fields

Yes, the word immutable comes up exactly once in Go spec. And that's when discussing type string. I think you should look at it more from the dual view points of Assignability and Addressability. For example Go will forbid you from rebinding variable to a different value of a type with unexported properties, obviously. Kinda like in C++ for classes not providing copy constructor, but in Go Pimpl feels a lot less awkward, befitting the goroutines' share by communicating philosophy.

"Mutability" only makes sense when you talk about some composite type, something that has "internal" parts, that perhaps can be changed independently of the thing that contains it. Strings are naturally composed of characters, and there is no mechanism in the language that lets us change a character in an existing string, short of assigning a whole new string, so we say that it is immutable.

For an int, it doesn't really make sense to talk about mutability, because, what are the "components" of an int? You change an int by assigning a whole new int, but assignment does not count as "mutating".

There is some connection between the issues of mutability and reference vs. value types. Semantically, there is no difference between an immutable reference type and a value type. Why? Suppose int was actually a pointer to an immutable object (i.e. *InternalIntObject with no functions for changing InternalIntObject). Once you assign such a pointer to a variable, it will forever represent the same integer value (can't be changed by others who share the same object) since the object is immutable. This is the same behavior as an integer value type. You can assign ints by assignment operator; likewise you can assign these pointers by assignment; the result would be the same: the assigned variable represents the same integer as what it was assigned to. Only difference would be the comparison and arithmetic operators would have to be re-defined to de-reference the pointer to compute the result.

Mutability is therefore only meaningful for reference types.

As for what you asked, the "mutable" types are generally considered to be the reference types except string: maps, channels, slices (with respect to the data pointed to by the slice), and also pointers to anything (since you can mutate the value at the location pointed to by the pointer).

Your concern seems to be more about allocation than immutability. Immutability certainly impacts allocation by making it impossible to reuse memory. A clever compiler could conceivably reuse any "immutable" memory whose address it knows doesn't escape.

Aside from strings, be careful with interfaces. Anything larger than word size will have to be allocated when assigned to the interface (optimizations aside). Also, variables declared in a loop body whose addresses escape, including via a closure, will have to be allocated each time through the loop. Otherwise, though, an assignment is just an assignment. The value just gets copied into the memory represented by the variable.

If you use make or new in a loop, or any literal that produces a reference, allocation will have to happen (again, subject to optimization).

Basically, it all boils down to trying to reuse memory where you can, and hoping the compiler does it for you when you can't, if it makes any sense to do so.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top