2

I am trying to find out in a := b if a will be a different copy of struct like func pass_by_value(a some_struct)

But I find that I don't understand the print statement.

Consider this go playground

    nested_level2 := test_assign_nested_level2{}
    nested_level1 := test_assign_nested{nested_level2}
    top_level := test_assign{nested_level1}

    assign := top_level
    fmt.Println("top_level address")
    fmt.Printf("%p", &top_level)
    fmt.Println(" ")
    fmt.Println("1 level address")
    fmt.Printf("%p", &top_level.Level1)
    fmt.Println(" ")
    fmt.Println("2 level address")
    fmt.Printf("%p", &top_level.Level1.Level_2)
    fmt.Println("------------------------")

    fmt.Println("assign top_level address")
    fmt.Printf("%p", &assign)
    fmt.Println(" ")
    fmt.Println("1 level address")
    fmt.Printf("%p", &assign.Level1)
    fmt.Println(" ")
    fmt.Println("2 level address")
    fmt.Printf("%p", &assign.Level1.Level_2)

The output of the above is

top_level address
0x10410020 
1 level address
0x10410020 
2 level address
0x10410020 
assign top_level address
0x10410024 
1 level address
0x10410024 
2 level address
0x10410024

I expect the output to be similar to

    fmt.Println("top_level address")
    fmt.Printf("%p", &top_level)
    fmt.Println(" ")
    fmt.Println("1 level address")
    fmt.Printf("%p", &nested_level1)
    fmt.Println(" ")
    fmt.Println("2 level address")
    fmt.Printf("%p", &nested_level2)
    fmt.Println(" ")
    fmt.Println(" ------------------------------- ")

where

top_level address
0x421152280 
1 level address
0x421152270 
2 level address
0x421152260 

each struct have a different address. but it seems like the child struct have the same address as the parent struct.

Why does all the nested element in the struct have the same address?

And does := actually copy a new struct recursively? Like the print statement indicated? (ie. := will return a brand new copy of struct with each of its field content also a brand new copy recursively)

11
  • 3
    All assignments in Go are copies. The address are the same, because you are taking the address of the same value every time. Experiment with putting some other values in those structs. Commented Sep 20, 2017 at 4:26
  • I am trying to print 6 different values, address of top_level , address of top_level. Level1 top_level.Level1.Level_2 etc..... Can you explain why they are all the same? Commented Sep 20, 2017 at 4:29
  • Even though assign := top_level, assign will have its own space in memory different from top_level as it is new assignment. Every reference of same location will return same location. Commented Sep 20, 2017 at 4:43
  • @user3591466: structs have no size other than what they contain, and you only have a single int value in them. What values do you expect to see? Commented Sep 20, 2017 at 4:50
  • @Godfrey it make sense assign has a different address than top_level since now i know that := will make a new copy of the operand recursively, but it does not make sense to have all the nested struct to have the same address as the parent struct. I must be getting something wrong here. Commented Sep 20, 2017 at 4:51

2 Answers 2

3

Types in Go are not autonomes wrappers around other things but just two things: Types allow to attach methods and types provide a layout in memory. For the question here the ability to attach methods to types is irrelevant. Let's take a look a neutral formulation of the question:

type A int64
type B { a A }
type C { b B }

This declares three types with the following memory layout:

  • Type A has the memory layout of a int64 (that is 8 bytes).
  • Type B has the memory layout of a single A, that is a int64, so 8 bytes.
  • Type C has the memory layout of a single B, that is a single A, that is a int64, so 8 bytes.

Type B in regard to memory layout is not a "wrapper" around A, at least the wrapper adds absolutely nothing. From a purely memory-layout perspective defining type B would be useless (but it allows to attach different methods to B than to A).

Now it should be clear that the address of a c C is that of the first of its 8 bytes and this is the same as c.b's address which is the same than c.b.a. And any assignment to a C is just a copy of one machine word (on 64bit architectures).

If you define type D { a A; b B } it gets more interesting as a D is now 16 bytes long. (Adding more to a D might even leave holes due to padding.) But still does D not provide anything (expect a new method set) to an A and a B adjacent to each other in memory.

Sign up to request clarification or add additional context in comments.

Comments

1

My guess is that you are looking for something like this:

package main

import "fmt"

// Nesting: type T2 struct{ F3 int }
type T2 struct{ F3 int }

// Nesting: type T1 struct{ { F2 struct{ F3 int } }
type T1 struct{ F2 T2 }

// Nesting: type T0 struct{ F1 struct{ F2 struct{ F3 int } } }
type T0 struct{ F1 T1 }

func main() {
    t2 := T2{F3: 42}
    fmt.Printf(
        "%p %p %d\n",
        // 0xc4200120d0 0xc4200120d0 42
        &t2, &t2.F3, t2.F3,
    )

    t1 := T1{F2: t2}
    fmt.Printf(
        "%p %p %p %d\n",
        // 0xc4200120f0 0xc4200120f0 0xc4200120f0 42
        &t1, &t1.F2, &t1.F2.F3, t1.F2.F3,
    )

    t0 := T0{F1: t1}
    fmt.Printf(
        "%p %p %p %p %d\n",
        // 0xc420012100 0xc420012100 0xc420012100 0xc420012100 42
        &t0, &t0.F1, &t0.F1.F2, &t0.F1.F2.F3, t0.F1.F2.F3,
    )
}

Output:

0xc4200120d0 0xc4200120d0 42
0xc4200120f0 0xc4200120f0 0xc4200120f0 42
0xc420012100 0xc420012100 0xc420012100 0xc420012100 42

For T0

type T0 struct{ F1 T1 }

type T1 struct{ F2 T2 }

type T2 struct{ F3 int }

is equivalent to

type T0 struct {
    F1 struct {
        F2 struct {
            F3 int
        }
    }
}

and T0, F1, F2, and F3 have the same address.


In your new example, T0

type T2 struct{ F3A, F3B int }

type T1 struct{ F2 T2 }

type T0 struct{ F1 T1 }

is equivalent to

type T0 struct {
    F1 struct {
        F2 struct {
            F3A int
            F3B int
        }
    }
}

and T0, F1, F2, and F3A have the same address. F3A and F3B have different addresses.

1 Comment

Sorry, I am still confused on why do they all have the same address? And why does the same address behavior only exist for the first field of the struct like in this playground?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.