🔥 포인터와 함수

325자
4분

함수에서 포인터를 활용하면 효율적이고 유연한 코드를 작성할 수 있어요. 예제 코드를 통해 포인터와 함수의 관계를 살펴보도록 하죠.

go
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
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))
}
 

위 코드에서 AbsScale 함수가 Vertex 구조체를 다루는 방식에 주목해 보세요.

Abs 함수는 Vertex 타입의 값을 받아서 해당 점의 원점으로부터의 거리를 계산합니다.

go
func Abs(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
 
go
func Abs(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
 
  • vVertex 타입의 값으로 전달되므로, 함수 내에서 v의 값을 변경해도 원본 Vertex에는 영향을 주지 않아요.

반면, Scale 함수는 Vertex 타입의 포인터를 받아서 해당 점의 좌표를 주어진 배율로 조정하죠.

go
func Scale(v *Vertex, f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}
 
go
func Scale(v *Vertex, f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}
 
  • vVertex의 포인터이므로, v를 통해 원본 Vertex의 값을 직접 변경할 수 있어요.

main 함수에서는 Scale 함수에 &v를 전달하여 v의 포인터를 넘기고 있어요.

go
func main() {
	v := Vertex{3, 4}
	Scale(&v, 10)
	fmt.Println(Abs(v))
}
 
go
func main() {
	v := Vertex{3, 4}
	Scale(&v, 10)
	fmt.Println(Abs(v))
}
 
  • Scale 함수가 v의 값을 변경하면, main 함수에서도 그 변경 사항이 반영되죠.

이제 Scale 함수의 매개변수에서 *를 제거해 볼까요? 어떤 일이 벌어질지 예상이 되시나요?

go
func Scale(v Vertex, f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}
 
go
func Scale(v Vertex, f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}
 

Scale 함수가 이제 Vertex 값을 직접 받게 되었습니다. 즉, 함수 내에서 v의 값을 변경해도 원본 Vertex에는 영향을 주지 않게 되죠.

main 함수에서 Scale 호출 시 & 연산자를 제거해야 컴파일 에러가 발생하지 않아요.

go
func main() {
	v := Vertex{3, 4}
	Scale(v, 10)
	fmt.Println(Abs(v))
}
 
go
func main() {
	v := Vertex{3, 4}
	Scale(v, 10)
	fmt.Println(Abs(v))
}
 

하지만 이 경우 Scale 함수는 v의 복사본을 받아 작업하므로, 원본 v의 값은 변경되지 않습니다. 결과적으로 Abs 함수에 전달되는 v는 여전히 {3, 4}인 셈이죠.

이렇게 포인터를 활용하면 함수가 원본 값을 직접 변경할 수 있어요. 함수의 매개변수로 값을 전달할지, 포인터를 전달할지는 함수의 의도와 설계에 따라 결정하면 되겠죠?

YouTube 영상

채널 보기
벡터의 정의와 덧셈 연산 | 선형대수학
BTree 노드의 구조는?
7편, 파이썬으로 구현하는 B-Tree
Trie 자료구조 완전 정복 - 개념부터 시각화까지 | Trie 자료구조 이야기
숫자 하나가 AI 모델의 운명을 바꾼다? | 선형대수학
AI는 왜 수백 차원의 벡터를 사용할까? 고차원 공간과 행렬 | 선형대수학
내적의 기하학적 의미와 코사인 유사도 원리 | 선형대수학
마지막편, 트라이 노드를 50% 이상 줄이는 방법? 압축 트라이 성능 분석 | Trie 자료구조 이야기