꽤 헷갈리는 Golang에서 포인터 다루기 (feat. 인터페이스,구조체)

타미·2021년 2월 5일
1

Hello Golang

목록 보기
4/7
post-thumbnail
  • 고랭에서는 포인터 타입을 제공한다.
    * 연산은 제공하지 않는다.
  • 포인터 변수를 인터페이스와 구조체에서 언제, 어떻게 사용하는지 알아보자!

struct에서 포인터 다루기

type Dog struct {
}

func (d Dog) run()  {
	println("run")
}
dog1 := &Dog{} // type: *Dog
dog1.run() 

dog2 := Dog{} // type: Dog
dog2.run()

C나 C++을 배운 사람에게는 상당히 이상한 코드이다!
고랭에는 화살표 연산자가 없어서, 포인터도 일반 객체처럼 행동할 수 있다.

func MyFunction(dog1 Dog, dog2 *Dog)  {
	// do something
}
MyTest(*d1, &d2)

포인터 객체인지, 일반 객체인지에 따라 함수 paramter에 맞춰서 넣어주어야 한다.

객체에서 포인터는 일반 객체와 명백히 다른 타입이며,
화살표 연산자가 없어 객체처럼 행동한다.


interface에서 포인터 다루기

이제 헷갈리는 건 interface에서 pointer가 결합되었을 때이다. Dog와 같은 동물을 추상화한 Animal interface를 추가해보자.


type Animal interface {
	run()
}

type Dog struct {
}

func (d Dog) run()  {
	println("run")
}

Animal interface에 정의된 함수를 구현했으므로, Dog는 Animal의 구현체가 된다.

animal1 := Dog{}
animal2 := &Dog{}

animal1Type := reflect.ValueOf(animal1).Type() // Dog
animal2Type := reflect.ValueOf(animal2).Type() // Dog

if animal1Type == animal2Type {
	println("animal1과 animal2는 서로 같은 타입니다.")
}
  • interface는 주소를 받을수도, 객체를 받을수도 있다.
  • interface의 type은 구현체를 따른다.

이런 현상이 가능한 이유는 interface 속이 생긴 구조 때문이다.

interface 데이터 형식

  • tab
    • dynamic type (구현체) 정보에 대한 포인터
  • data
    • dynamic type 데이터에 대한 포인터

자세한 건 나중에 알아보기로 하고 여기서 중요한 건 interface 내부에는 포인터가 저장된다는 사실이다. 그냥 value를 넣어주어도 내부에서는 주소를 저장하기 때문에, 주소를 넣어준 것과 같은 효과라는 것이다.

Point Recevier


type Animal interface {
	run()
}

type Dog struct {
}

//func (d Dog) run()  {
//	println("run")
//}

func (d *Dog) run() {
	println("run")
}

Dog 객체가 Value Receiver가 아닌 Point Receiver로 함수를 구현했다고 바꾸어보자.

var animal Animal
animal = Dog{} // nope
animal = &Dog{} // ok


var dog Dog = Dog{} // ok

animal = Dog{} 여기서에는 Cannot use 'Dog{}' (type Dog) as type Animal Type does not implement 'Animal' as 'run' method has a pointer receiver 라는 이유로 오류가 생긴다.
Pointer receiver 함수를 접근하기 위해서는 dog의 포인터가 필요한데 그게 없어서라고 생각이 되는데, 어차피 interface 내부에서는 포인터를 가지고 있으니 상관없지 않나? 아직 잘 모르겠음

profile
IT's 호기심 천국

0개의 댓글