Three conclusions about GO slices and arrays
It is well known that changing the value of a field in a method has no effect on the outside world depending on whether the method is of value type or pointer type
func (s Struct)setX(a){... }// The value method is invalid
func (s *Struct)setY(a){... }// The pointer method takes effect
Copy the code
Similarly, changing an argument in a function to the outside world depends on whether the argument is of a value type or a reference type
i := 1
func setI(I int) { I = 2 } // The parameter is of invalid value type
setI(i) // i: 1
j := &i
func setJ(J *int) { *J = 2 } // The parameter is valid by reference type
setJ(j) // j: 2
Copy the code
For j of type *int, reassignment to it also applies to the outside world. But that’s not the case with array and slice types.
Let me start with my conclusion
- Partial changes to slices in the function are applied to the outside world
- The GO array is a value type, and part of the change array is not reflected
- The slicing layer maintains a pointer to an array
And then I can prove my conclusion with code
Conclusion 1: Some changes to a reference type value in a function take effect externally
// Section changes take effect
s := []int{2: 0} // []int [0 0 0]
func fa(S []int) { S[0] = 1 }
fa(s) // []int [1 0 0]
Copy the code
But reassigning a variable inside a function does not apply to the outside world. This is a common “pass value” and “pass reference” problem in other languages
// Slice reassignment is invalid
s1 := []int{2: 0} // []int [0 0 0]
func fb(S []int) { S = []int{} }
fb(s1) // []int [0 0 0]
Copy the code
Conclusion 1: The method behaves the same as the function, and changes that should not take effect in the instance (because it is a value method) do take effect because the value of the reference type is partially changed in the method
// Data preparation
type s struct{ x []int }
ss := s{[]int{2: 0}} // main.s {𒀸x:[0 0 0]}
// The value method partially changed but took effect
func (ss s) setX(a) { ss.x[1] = 1 }
ss.setX() // main.s {𒀸x:[0 1 0]}
// The value method reassignment is invalid
func (ss s) setY(a) { ss.x = []int{1} }
ss.setY() // main.s {𒀸x:[0 1 0]}
Copy the code
Conclusion 2: The GO array is a value type, and partial changes to the array are not reflected
The fact that the code var arr [3]int = nil returns an error confirms that the array is a value type. Because only null values of reference types can be nil
But it’s a little counterintuitive to partially change the array without reflecting to the outside world
// The array part is invalid
arr := [3]int{} // [3]int [0 0 0]
func fc(Arr [3]int) { Arr[0] = 1 }
fc(arr) // [3]int [0 0 0]
Copy the code
In fact, if you think about it, changing the value of a structure in a function cannot be passed to the outside world
type s struct{ x int }
func fd(S s) { S.x = 1 }
var ss s / / the main s {𒀸 x: 0}
fd(ss) / / the main s {𒀸 x: 0}
Copy the code
It is because of these two “dead rules” of arrays and structures that value types are truly distinguished from pointer types. This way the intent of the method is more obvious and the caller is less worried
By the way, changing arrays inside Java methods also works. Because arrays are also complex types
import static java.lang.System.out;
public class a {
public static void main(String[] args) {
// Create an array -> 0 0 0
var arr = new int[3];
for (int i : arr) out.print(i + "");
out.println();
// After some changes -> 1 0 0
setArr(arr);
for (int i : arr) out.print(i + "");
}
public static void setArr(int[] arr) {
arr[0] = 1; }}Copy the code
Conclusion 3: Slicing maintains a pointer to an array and creates a slicing that “points” to an array. Partially changing the array also changes the value of the slice
a2 := [3]int{}
s2 := a2[:]
a2; s2 // [3]int [0 0 0]; []int [0 0 0]
a2[0] = 1;
a2; s2 // [3]int [1 0 0]; []int [1 0 0]
Copy the code
Try the append section (it will expand due to the length of the data)
After capacity expansion, there is no correlation between the two, and changes made to either side will not be synchronized to the other