英文:
Rule for Go Pointers, References, Dereferencing:
问题
我是GoLang的新手,来自Delphi和C++的世界,对这门语言非常兴奋,我认为它注定会成为"下一个大事件"。
我试图理解Go解析器和编译器如何处理指针和引用,但似乎找不到任何明确规定的地方。
在下面的代码示例中,返回类型*list.List
和局部变量l
都是指针类型,在声明时需要指针符号*
,但在使用时不需要解引用:l.PushBack(i)
。但是在同样的代码中,输入参数value *int64
被声明为指针,必须解引用才能正确使用:var i int64 = *value / 2
。
我猜想这是因为list.List
是引用类型,所以在使用时解引用是隐式的,而int64
是值类型,必须像在C++中处理任何值类型的指针一样进行处理:必须解引用。
让我感到困惑的是,即使*list.List
必须使用*
声明为指针类型,但在使用列表实例时,不需要解引用。这最初让我感到非常困惑。这只是"事情的本质",还是我漏掉了什么?
示例代码:
func GetFactors(value *int64) *list.List {
l := list.New()
l.PushBack(*value)
var i int64 = *value / 2
for ; i > 1; i-- {
if *value%i == 0 {
l.PushBack(i)
}
}
return l
}
英文:
I am new to GoLang, coming from the Delphi, C++ world - admittedly very excited about this language, which I think is destined to become "the next big thing".
I am trying to get a handle around how the Go parser and compiler handle pointers and references - can't seem to find any place where some clear rules are laid out.
In the below code sample for example, the return type *list.List
and the local variable l
are pointer types and require the pointer symbol *
in their declarations, but they don't have to be dereferenced in use: l.PushBack(i)
. But in this same code the input parameter value *int64
is declared as a pointer and has to be dereferenced to be used properly: var i int64 = *value / 2
I assume that this is because list.List
is a reference type, so the dereferencing is implicit when used, while int64
is a value type and must be handled just as any pointer to a value type, as in C++ for example: It must be dereferenced.
What is confusing to me is that even though *list.List
has to be declared as a pointer type using *
, when using the list instance, dereferencing is not required. This had me quite confused initially. Is that "just the way it is", or am I missing something?
Sample:
func GetFactors(value *int64) *list.List {
l := list.New()
l.PushBack(*value)
var i int64 = *value / 2
for ; i > 1; i-- {
if *value%i == 0 {
l.PushBack(i)
}
}
return l
}
答案1
得分: 15
List
的所有方法都有*List
作为接收者:(http://golang.org/pkg/container/list/)
func (l *List) Back() *Element
func (l *List) Front() *Element
func (l *List) Init() *List
...
func (l *List) Remove(e *Element) interface{}
在你的示例中,l
的类型是*List
,所以不需要对它们进行解引用。
假设,相反,你有这样的代码:
type A struct{}
func (a A) X() {
fmt.Println("X")
}
func (a *A) Y() {
fmt.Println("Y")
}
你可以这样写:
a := A{}
a.X()
a.Y() // == (&a).Y()
或者你可以这样写:
a := &A{}
a.X() // 等同于 == (*a).X()
a.Y()
但这只适用于方法的接收者。Go 不会自动转换函数参数。给定以下函数:
func A(x *int) {
fmt.Println(*x)
}
func B(y int) {
fmt.Println(y)
}
这是无效的:
A(5)
你必须这样写:
var x int
A(&x)
这也是无效的:
var y *int
B(y)
你必须这样写:
B(*y)
与 C# 或 Java 不同,当涉及到结构体时,Go 不区分引用类型和值类型。*List
是一个指针,List
不是。修改List
上的字段只会修改本地副本。修改*List
上的字段会修改所有的“副本”(因为它们并不是副本...它们都指向内存中的同一位置)。
有些类型似乎隐藏了底层指针(比如切片包含一个指向数组的指针),但是 Go 总是按值传递。
英文:
All of the methods for a List
have *List
receivers: (http://golang.org/pkg/container/list/)
func (l *List) Back() *Element
func (l *List) Front() *Element
func (l *List) Init() *List
...
func (l *List) Remove(e *Element) interface{}
In your example l
is of type *List
, so there's no need to dereference them.
Suppose, instead, that you had something like this:
type A struct{}
func (a A) X() {
fmt.Println("X")
}
func (a *A) Y() {
fmt.Println("Y")
}
You are allowed to write:
a := A{}
a.X()
a.Y() // == (&a).Y()
Or you can do the following:
a := &A{}
a.X() // same like == (*a).X()
a.Y()
But it only works for method receivers. Go will not automatically convert function arguments. Given these functions:
func A(x *int) {
fmt.Println(*x)
}
func B(y int) {
fmt.Println(y)
}
This is invalid:
A(5)
You have to do this:
var x int
A(&x)
This is also invalid:
var y *int
B(y)
You have to do this:
B(*y)
Unlike C# or Java, when it comes to structs, Go does not make a distinction between reference and value types. A *List
is a pointer, a List
is not. Modifying a field on a List
only modifies the local copy. Modifying a field on a *List
modifies all "copies". (cause they aren't copies... they all point to the same thing in memory)
There are types which seem to hide the underlying pointer (like a slice contains a pointer to an array), but Go is always pass by value.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论