GoLang 뉴비로 엄청 했갈렸던 부분이 있다.
함수 parameter로 어떤 데이터를 넘기고, 함수 내에서 변경이 생겼을 때 어쩔 때는 변경이 반영되고 어쩔 때는 변경이 반영되지 않는다는 것이다! 찾아보니 간단한 내용이었는데 처음 공부하는 사람은 헷갈리는 부분이라 정리해본다 :>
GoLang은 기본적으로 Call By Value를 지원한다.
JAVA와 달리, GoLang은 기본적으로 Call By Value를 지원한다.
Call By Reference를 하고 싶으면 포인터로 넘겨주는 방식이다.
// call by value
func change1 (num int) {
num = 100
}
// call by reference
func change2 (num *int) {
&num = 100
}
num := 1
change1(num) // num == 1, 변경 X
change2(&num) // num == 100, 변경 O
기본적으로 Call By Value 방식으로 동작하며, 이후 데이터가 Value Type인지 Reference Type인지에 따라 동작이 다르다.
struct
int
Map
Slice
string
Value Type이든 Reference Type이든,
Call By Value 방식이기 때문에 함수를 실행하면 해당 데이터를 복사하여 사용한다.
type Student struct {
name string
age int
}
func Change1(student Student) {
student.age += 10
}
func Change2(student *Student) {
(*student).age += 10
}
student := Student{"Tommy", 26}
Change1(student) // 결과값: Tommy, 26
Change2(student) // 결과값: Tommy, 36
Change1
함수를 호출한 main 함수
Change1 (Call By Value)는 Student 내부 데이터를 복사해왔지만, Value Type이기 때문에 원본 데이터와 다른 주소값에 존재한다. -> 실질적으로 원본 데이터에 영향을 주지 못한다.
Change2의 경우 원본 데이터의 주소를 그대로 가지기 때문에 데이터를 바꿀 수 있다.
func (w *Wallet) DepositWithValueReceiver(amount int) {
w.balance += amount
}
// Production add: 0xc000016378, value: 0
// Test add: 0xc000016378, value: 10
(*w).balance += amount
와 같다.Reference Type도 Call By Value이기 때문에 Value Type과 마찬가지로 parameter로 전달한 데이터만 복사한다. 다만 Reference Type 자체가 주소로 변경되기에 함수에서의 변경이 영향이 가는 것이다.
Slice를 통해 좀 더 자세히 알아보자
Slice의 구성요소
요기 3개는 stack에 있고, 데이터가 있는 array는 heap영역에 존재한다.
func Change1(numbers []int) {
numbers[0] = 1000 // 주소: 0xc00004e6e8
}
numbers := make([]int, 10)
numbers[0] = 1 // 주소: 0xc00004e6e8
Change1(numbers) // numbers[0] = 1000으로 변경된다.
Change1 함수에 갔을 때 있는 것은 numbers의 Ptr, len, cap이다.
이 중 ptr로 array에 접근하기 때문에 변경이 반영된다.
func Change1(numbers []int) {
numbers = append(numbers, 1000)
}
numbers := make([]int, 3)
numbers[0] = 1 // {1,0,0}
Change1(numbers)
정답은 {1,0,0} 그대로이다.
append하여 array 내부적으로는 {1,0,0,1000}이 되지만 numbers의 len,cap 때문에 4번째 데이터를 볼 수 없는 것이다.
slice는 append할 때 len,cap 변수를 조정해줘야 하기 때문에 포인터 변수로 넘겨야 한다!