Hello, playground 0 0x0 0x0 0 0x0 0x0 0 0x0 0x0
var a Aprintln(a.i, a.s, a.m, a.c)b := A{}println(b.i, b.s, b.m, b.c)
c := *new(A)println(c.i, c.s, c.m, c.c)
Do they do allocate in different places - stack or heap? For me, they all do the same thing declaring a value variable, so it isn't obvious to pick the "proper" one.
Effectively nothing.
> Do they do allocate in different places - stack or heap?
"Stack" or "heap" allocation is abstracted away from the programmer in Go.
> Which one is the ideomatic and (mainly) why?
The end result of all of these operations is a variable (a, b or c)
which represents an "A" structure by value, with no explicit
initialization, ie. all members of "A" with their default values. The
'b' form is probably the most idiomatic, because it can easily accept
explicit initialization:
b := A{1, "abc"}
or be transformed to referring to an "A" structure by reference:
b := &A{}
A case can be made for the 'a' form in some circumstances. The 'c'
form is a bit circuitous. (I've not used the "new" keyword in a long,
long time.)
Not to nit-pick, but c here has the type A, since it has been
dereferenced explicitly, no?
- Jim
c := *new(A)println(c.i, c.s, c.m, c.c)Here, c will have the type *A, which is a pointer to A. Those types are distinct, but when you access an attribute of c, the Go compiler will automatically dereference the pointer first. Alternatively, and a bit more idomatic is it to write "d := &A{}". Here, d will also be a *A.
Not to nit-pick, but c here has the type A, since it has been
dereferenced explicitly, no?
Personally, I use := when I just am doing a simple assignment,
function call, etc. I think that I only use var when I'm pre-declaring
something that will be used in a later block. Since its not being
initialized, I have to make sure the type is specified, and it helps
to make that bit of code a bit more clear.
As for composite literal &Typename{} versus new(Typename), I use the
former when I am completely initializing a new object that I am
creating, and the latter when the relationship between my objects
means that that will be an in-between state where the new Typename is
not fully set up until I've done something else. For example:
// Two objects that refer to each other, could do this:
foo := &Foo{
bar: &Bar{}
}
bar := foo.bar
bar.foo = foo
But I'd probably do that this way instead:
foo := new(Foo)
bar := new(Bar)
foo.bar = bar
bar.foo = foo
Contrived, but those are the (kind of) guidelines that I use.
- Jim
Using the ":=" operator doesn't work for package-level variables. Also
if you want a zero value for a particular type. I think "var i int16"
is clearer than "i := int16(0)".
The ":=" operator also has a bonus if you want to declare a single new
variable to accept one out of multiple return values:
func whatsit() (foo []byte, err error) {
f, err := os.Open("filename") // assigns to existing "err"
if err != nil { return }
foo, err = ioutil.ReadAll(f)
return
}
--
matt kane's brain
http://hydrogenproject.com