在下面的代码片段中,我想了解当其内容仍未初始化时
如果
以下是代码:
(这个问题是我对我在为什么 io.Writer.String() 运行时错误的精确事实正确性的回答产生了犹豫。所以我决定尝试进行一些调查,了解Go语言中接口变量和赋值工作的具体情况。) 编辑:在收到几个有用的答案后,我仍然感到困惑:
改变第一行可以解决这个问题:
iPerson
存储了什么:只是0字节的值吗?还是它实际上是一个指针(当然也初始化为0字节)?无论如何,在iPerson = person
发生了什么?如果
iPerson = person
复制了person
,那么当分配给iPerson
一个具有不同尺寸/内存占用的实现IPerson
对象时会发生什么呢?我理解iPerson
是存储在堆栈上的变量,因此其大小必须固定。这是否意味着堆实际上在背后被使用,所以iPerson
实际上是作为指针实现的,但分配仍然复制对象,正如以上代码所示?以下是代码:
type Person struct{ name string }
type IPerson interface{}
func main() {
var person Person = Person{"John"}
var iPerson IPerson
fmt.Println(person) // => John
fmt.Println(iPerson) // => <nil> ...so looks like a pointer
iPerson = person // ...this seems to be making a copy
fmt.Println(iPerson) // => John
person.name = "Mike"
fmt.Println(person) // => Mike
fmt.Println(iPerson) // => John ...so looks like it wasn't a pointer,
// or at least something was definitely copied
}
(这个问题是我对我在为什么 io.Writer.String() 运行时错误的精确事实正确性的回答产生了犹豫。所以我决定尝试进行一些调查,了解Go语言中接口变量和赋值工作的具体情况。) 编辑:在收到几个有用的答案后,我仍然感到困惑:
iPerson = person
iPerson = &person
两者都是合法的。然而,对我来说,这引出了一个问题:为什么编译器允许出现如此弱类型的情况?上述情况的一个含义是:
iPerson = &person
var person2 = iPerson.(Person) # panic: interface conversion: interface is *main.Person, not main.Person
改变第一行可以解决这个问题:
iPerson = person
var person2 = iPerson.(Person) # OK
因此,静态地确定iPerson
是持有指针还是值是不可能的;似乎任何东西都可以在运行时将任何一种类型赋值给它,而不会引发任何错误。为什么要做出这样的设计决策?它有什么作用?它显然不符合“类型安全”的思维方式。
iPerson = &person
和iPerson = person
两种方式,而不需要改变iPerson
的类型。这样会导致运行时类型错误,而这些错误本可以在静态时期被捕获。这是Volker提出的文章没有涉及或者提到的问题。 - Erik KaplunPerson
值。如果你改为使用iPerson.(*Person)
,你就可以成功地检索到该值。 - James Henstridge