0

Here is the struct BiOperators. It implements MyInterface1 (using BiOperators as method receiver). These are just some code for testing and I omit it here.

type BiOperators struct {
    oprt1 float64
    oprt2 float64
}

My question is why I can't assign value to oprt1 after type assertion

func testTypeAssertion() {
    bio := BiOperators{111, 222}

    arr := []MyInterface1{bio, &bio}

    // I can do the conversion and output field oprt2
    fmt.Println((arr[0].(BiOperators)).oprt2)

    // But when I want to directly assign value to it, I got the following error
    // cannot assign to arr[0].(BiOperators).oprt2go

    // (arr[0].(BiOperators)).oprt2 = 99 <----this line is error

    // and I can't create a pointer to do the assignment
    // the following line has error : cannot take the address of arr[0].(BiOperators)go
    // bioCvt2 := &(arr[0].(BiOperators)) <----this line is error too

    // I can using the following lines to do the assignment. But it will create a new struct
    bioCvt := (arr[0].(BiOperators))

    bioCvt.oprt2 = 333

    fmt.Println("bioCvt", bioCvt)
    fmt.Println("arr[0](assigned using bio)", arr[0])

}

So is there anyway to NOT create a new struct after type assertion to do the field assignment?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
DeepNightTwo
  • 4,809
  • 8
  • 46
  • 60
  • 3
    Type assertion expression returns a value, and that value is *always* a copy of the value stored inside the interface. Doing the assignment directly the way you want, to a non-pointer value copy, will result is something you do *not* want, and this is obvious to the compiler which is why it protests and tells you to fix your code. If you store a pointer in the interface, however, the result will be what you want and it is therefore allowed by the compiler. Try it yourself, change `arr[0]` to `arr[1]` which is where you have `*BiOperators`. – mkopriva Jan 24 '21 at 06:56
  • 1
    And note that `&(arr[0].(BiOperators))` breaks because you cannot get the pointer of an [unaddressable](https://golang.org/ref/spec#Address_operators) value. – mkopriva Jan 24 '21 at 07:02
  • Type assertion expression always create a copy of the original value. This is so different with java. Thanks for your answer. It helps a lot for a 14 years javaer (and have few C background). – DeepNightTwo Jan 25 '21 at 05:13

1 Answers1

2

When you put bio into the interface array, a copy of bio is made and stored in the zeroth element. The first element contains a pointer to bio so no copy is made for that element. Similarly, when you cast from the interface back to the struct type, another copy of the value is made. Presumably the compiler or language does not allow this because you'd be modifying a copy that you cannot access again to use the value in any way.

Even with your code above, something similar still happens. When the field on bioCvt is modified, it does not modify bio at all because you are modifying a copy.

However, if you cast the first element to a pointer instead, you can modify it, which is the underlying value in bio:

func testTypeAssertion() {
    bio := BiOperators{111, 222}

    arr := []MyInterface1{bio, &bio}

    (arr[1].(*BiOperators)).oprt2 = 99 // does not error anymore

    fmt.Println("arr[1](assigned using bio)", arr[1])
    fmt.Println("bio", bio) // This will print 99
}