🔥 포인터와 함수
325자
4분
함수에서 포인터를 활용하면 효율적이고 유연한 코드를 작성할 수 있어요. 예제 코드를 통해 포인터와 함수의 관계를 살펴보도록 하죠.
package main import ( "fmt" "math" ) type Vertex struct { X, Y float64 } func Abs(v Vertex) float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func Scale(v *Vertex, f float64) { v.X = v.X * f v.Y = v.Y * f } func main() { v := Vertex{3, 4} Scale(&v, 10) fmt.Println(Abs(v)) }
go
위 코드에서 Abs
와 Scale
함수가 Vertex
구조체를 다루는 방식에 주목해 보세요.
Abs
함수는 Vertex
타입의 값을 받아서 해당 점의 원점으로부터의 거리를 계산합니다.
func Abs(v Vertex) float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) }
go
v
는Vertex
타입의 값으로 전달되므로, 함수 내에서v
의 값을 변경해도 원본Vertex
에는 영향을 주지 않아요.
반면, Scale
함수는 Vertex
타입의 포인터를 받아서 해당 점의 좌표를 주어진 배율로 조정하죠.
func Scale(v *Vertex, f float64) { v.X = v.X * f v.Y = v.Y * f }
go
v
는Vertex
의 포인터이므로,v
를 통해 원본Vertex
의 값을 직접 변경할 수 있어요.
main
함수에서는 Scale
함수에 &v
를 전달하여 v
의 포인터를 넘기고 있어요.
func main() { v := Vertex{3, 4} Scale(&v, 10) fmt.Println(Abs(v)) }
go
Scale
함수가v
의 값을 변경하면,main
함수에서도 그 변경 사항이 반영되죠.
이제 Scale
함수의 매개변수에서 *
를 제거해 볼까요? 어떤 일이 벌어질지 예상이 되시나요?
func Scale(v Vertex, f float64) { v.X = v.X * f v.Y = v.Y * f }
go
Scale
함수가 이제 Vertex
값을 직접 받게 되었습니다. 즉, 함수 내에서 v
의 값을 변경해도 원본 Vertex
에는 영향을 주지 않게 되죠.
main
함수에서 Scale
호출 시 &
연산자를 제거해야 컴파일 에러가 발생하지 않아요.
func main() { v := Vertex{3, 4} Scale(v, 10) fmt.Println(Abs(v)) }
go
하지만 이 경우 Scale
함수는 v
의 복사본을 받아 작업하므로, 원본 v
의 값은 변경되지 않습니다. 결과적으로 Abs
함수에 전달되는 v
는 여전히 {3, 4}
인 셈이죠.
이렇게 포인터를 활용하면 함수가 원본 값을 직접 변경할 수 있어요. 함수의 매개변수로 값을 전달할지, 포인터를 전달할지는 함수의 의도와 설계에 따라 결정하면 되겠죠?