【问题标题】:Object instantiation by reference通过引用实例化对象
【发布时间】:2018-05-07 16:13:27
【问题描述】:

这是一个我不太明白的 Go 代码示例:

type MyClass struct {
    field1      string
    field2      string
}
...
objectinstance1 := MyClass{field1:"Hello", field2:"World"}
objectinstance2 := &MyClass{field1:"Hello", field2:"World"}

我可以用相同的语法对objectinstance1objectinstance2(例如方法调用)做完全相同的事情。

所以我不明白 & 运算符的作用。我的理解是objectinstance1 包含一个对象,而objectinstance2 包含一个指针。

对我来说,在 C 语言中与 char 和 char* 之间的区别是一样的。

但在这种情况下,我应该使用 -> 而不是 . (点)?

【问题讨论】:

标签: go


【解决方案1】:

差异不可见,因为它隐藏在两件事中:

  1. 运算符:= 同时为变量赋值和类型。所以看起来objectinstance1objectinstance2 是一样的。但实际上 first 是 MyClass 实例, second 是指向它的指针。如果使用长格式运算符会更明显:

    var objectinstace1 MyClass = MyClass{} var objectinstance2 *MyClass = &MyClass{}

如果你省略*& 变量和类型变得不兼容并且赋值失败。

  1. 隐式指针间接。 Go 在 ptr1.Field1 之类的语句中自动执行此操作,以通过指针访问 struct 中的特定字段。

    只有在有歧义的极少数情况下,您才必须使用完整形式:

    *ptr1.Value1

    有时甚至:

    (*ptr1).Value1

更新

显式指针用于消歧:

type M map[int]int

func (m *M) Add1() {
    // this doesn't work -  invalid operation: m[1] (type *M does not support indexing)
    // m[1] = 1

    // the same - invalid operation: m[1] (type *M does not support indexing)
    // *m[1] = 1

    // this works
    (*m)[1] = 1
}

https://play.golang.org/p/JcXd_oNIAw

【讨论】:

  • 谢谢,但是会出现什么样的歧义?
  • 例如,地图中的 @Bob5421。直到我写了(*ptr)[key],Go 才编译。否则我会得到像“指针不可下标”这样的错误。
【解决方案2】:

& 运算符为您提供指向结构的指针,而不使用它为您提供结构值。

最重要的地方是当你把这个结构传递给另一个函数时——如果你传递你使用& 运算符创建的指针,另一个函数可以访问 same结构。如果那个函数改变了它,你也得到了改变的结构。

如果你传递你在没有& 操作符的情况下创建的变量,你传递给它的函数有一个结构的副本。该函数或任何其他函数都无法更改您在变量中看到的内容。

这有效地使 value 变量在多个 go 例程中安全使用,没有竞争条件 - 每个人都有自己的结构副本。

如果您将使用& 生成的指针传递给其他 go 例程,则所有人都可以访问 same 结构,因此您真的希望这是有意并考虑的。

【讨论】:

    【解决方案3】:

    在 go 中,& operator 获取其参数的地址并将pointer 返回到参数的类型。

    指针间接自动发生,因此没有-> 运算符,点运算符处理所有类型的所有字段(成员)操作和访问,无论是指针还是结构。

    package main
    
    import (
      "fmt"
      "reflect"
    )
    
    func main() {
      type Foo struct{ name string }
      foo1 := Foo{"Alpha"} // A plain struct instance.
      foo2 := &Foo{"Bravo"} // A pointer to a struct instance.
      fmt.Printf("foo1=%v, name=%v\n", reflect.TypeOf(foo1), foo1.name)
      fmt.Printf("foo2=%v, name=%v\n", reflect.TypeOf(foo2), foo2.name)
      // foo1=main.Foo, name=Alpha
      // foo2=*main.Foo, name=Bravo
    }
    

    【讨论】:

      【解决方案4】:
      But in this case i should use -> instead of . (dot) ?
      

      没有。 Golang 不是 C 不是 Golang。在 Golang 中没有->。您也可以使用点 (.) 作为指针。 Golang 本来就是简单的,如果意图很明确,那么引入另一个运算符是没有意义的(指针上的 . 比调用方法还有什么意义?)

      【讨论】:

        猜你喜欢
        • 2022-01-17
        • 2011-07-02
        • 1970-01-01
        • 1970-01-01
        • 2013-01-24
        • 1970-01-01
        • 2018-10-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多