This is a creation in Article, where the information may have evolved or changed.
Issues with reference and pass-through
Many unofficial documents and textbooks (including some already published books), commentary on the Go language and references
Have a lot of problems. There are many misconceptions about the function parameters of go that lead to many novice go languages.
Communication and reference are the fundamental problems of programming languages, and if this problem is understood incorrectly it can cause many problems.
Chuan Slice is not a reference!
First of all, the function call parameters of the go language are all values, including slice
/ map
/ chan
in all types, without reference to the argument.
For details, see the code for the Go language:
After they is evaluated, the parameters of the call is passed by value to the function and the called function Begins execution.
From:http://golang.org/ref/spec#calls
What do you mean by reference?
For example, the following code is available:
var a ObjectdoSomething(a) // 修改a的值print(a)
If the function doSomething
modifies a
the value and then print
prints out the modified value,
Then you can assume that the doSomething
parameter is used in a reference way a
.
Why preach slice is not a reference?
We construct the following code:
func main() { a := []int{1,2,3} fmt.Println(a) modifySlice(a) fmt.Println(a)}func modifySlice(data []int) { data = nil}
Where modifySlice
the slices are modified a
, the output is as follows:
[1 2 3][1 2 3]
Note that a
modifySlice
there is no change before and after the call, so it a
must be a value!
Why do many people mistakenly think that slice is a reference?
It may be that the FAQ says slice is a reference type, but not a reference!
The following code may be the source of the error:
func main() { a := []int{1,2,3} fmt.Println(a) modifySliceData(a) fmt.Println(a)}func modifySliceData(data []int) { data[0] = 0}
The output is:
[1 2 3][0 2 3]
The function modifySliceData
does modify the contents of the slice through parameters.
Note, however, that there are many mechanisms for modifying the contents of a parameter through a function, in which the address of the parameter can be modified to modify the value of the parameter (in fact, it is the data that the pointer points to in the parameter), not just a way of referencing!
Is it equivalent to passing pointers and passing references?
For example, the following code is available:
func main() { a := new(int) fmt.Println(a) modify(a) fmt.Println(a)}func modify(a *int) { a = nil}
The output is:
0xc0100000000xc010000000
You can see that a
the pointer itself does not change. Passing a pointer or a pass-through address can only modify the value of memory pointed to by the pointer.
You cannot change the value of the pointer itself.
Therefore, the function parameter pass-through pointer is also the pass value, is not the reference!
All types of function parameters are value-passed!
slice
both the map
chan
underlying type and the custom type, including//, are value-passed.
However slice
, because map
of the differences between the structure and/or the chan
underlying structures, the effect of their values is not exactly equal.
The emphasis is summarized as follows:
gospec:the parameters of the call is passed by value!
map/slice/chan are all pass values, not reference
map/chan corresponding pointer, and reference similar to
slice is a mix of structs and pointers
slice including values/count/capacity information, is passed by value The values in
slice are pointers, passed by value
Slice by value can only modify the data that values point to, None of the others can modify the
Does the go language have a quote?
The go language is also a reference place, but is not a function of the parameters, but the closure of the external environment is accessed by reference.
Look at the following code:
func main() { a := new(int) fmt.Println(a) func() { a = nil }() fmt.Println(a)}
The output is:
0xc010000000<nil>
Because closures are variables that use the external environment by reference a
, the values can be modified directly a
.
For example, the output of the following 2-segment code is quite different, because the second code outputs the variable in the form of a closure reference i
:
for i := 0; i < 5; i++ { defer fmt.Printf("%d ", i) // Output: 4 3 2 1 0}fmt.Printf("\n") for i := 0; i < 5; i++ { defer func(){ fmt.Printf("%d ", i) } () // Output: 5 5 5 5 5}
Like the second code is the side effect of the closure reference, the way to avoid this side effect is to construct a different temporary variable by the parameter value or each closure:
// 方法1: 每次循环构造一个临时变量 ifor i := 0; i < 5; i++ { i := i defer func(){ fmt.Printf("%d ", i) } () // Output: 4 3 2 1 0}// 方法2: 通过函数参数传参for i := 0; i < 5; i++ { defer func(i int){ fmt.Printf("%d ", i) } (i) // Output: 4 3 2 1 0}
What is a reference type, and how does a pointer differ/relate?
Described in the official Go Language FAQ, maps
/ slices
/ channels
is a reference type and the array is a value type:
Why is maps, slices, and channels references while arrays is values?
There's a lot of history on that topic. Early on, maps and channels were syntactically pointers and it is impossible to declare or use a Non-pointer instance. Also, we struggled with how to arrays should work. Eventually we decided the strict separation of pointers and values made the language harder to use. Changing these types to act as references to the associated, shared data structures resolved these issues. This change added some regrettable complexity to the language it had a large effect on Usability:go became a more produc tive, comfortable language when it was introduced.
From:http://golang.org/doc/faq#references
I personally understand that reference types and pointers are the same on the underlying implementations.
However, the reference type hides the pointer operation that is displayed on the syntax.
Reference/pass-through values are not a concept for referential types and function parameters.
We know maps
/ slices
/ channels
at the bottom though the pointers are implied,
However, there is no syntax to use pointers in use.
The reference memory is, after all, based on pointer implementations, so a function must be relied upon/to be make
new
constructed.
Of course, they all support literal syntax constructs, but they still need a construction process in essence.
To use the reference type of the go language, it is important to understand some of the underlying structures (especially slice
the hybrid structure).
We can simulate a reference type for the go language ourselves.
We can define a value type-specific array type as a reference type (while providing a constructor):
type RefIntArray2 *[2]intfunc NewRefIntArray2() RefIntArray2 { return RefIntArray2(new([2]int))}
This allows us to RefIntArray2
use it as a reference type.
func main() { refArr2 := NewRefIntArray2() fmt.Println(refArr2) modifyRefArr2(refArr2) fmt.Println(refArr2)}func modifyRefArr2(arr RefIntArray2) { arr[0] = 1}
The output is:
&[0 0]&[1 0]
The reason for choosing an array as an example is that the go language array pointer can be accessed directly using []
the syntax sugar.
Therefore, the reference type is generally the underlying pointer implementation, only the upper layer with the syntax of sugar only.
Note: This section complements the comments made by @hooluupog and @LoongWong.
Summarize
- function parameter pass value, closed packet to quote!
- Slice contains values/count/capacity and other information, is passed by value
- Slice that are passed by value can only modify the data pointed to by values, and none of the others can be modified
- Slice is a mixture of structures and pointers
- Reference types and pass-through references are two concepts
from:http://my.oschina.net/chai2010/blog/161384