인터페이스 할당이 메서드 호출보다 더 엄격한 이유는 무엇입니까?

Aug 20 2020

Tour of Go를 진행 중입니다. 포인터를 수신자로 받아들이는 메서드가 있으면 값 유형도 수신자로 받아 들일 것임을 배웠습니다 (go가 자동으로 변환을 수행함).

type Vertex struct { X, Y float64 }

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X * v.X + v.Y * v.Y)
}

그런 다음 Vertex가 값 또는 포인터로 수신되는지 여부에 관계없이 다음 코드가 유효합니다.

v := Vertex{1, 2}
fmt.Println(v.Abs())

p := &v
fmt.Println(p.Abs())

그러나 다음과 같은 인터페이스가 있다고 가정 해 보겠습니다.

type Abser interface {
    Abs() float64
}

그렇다면 다음 코드가 잘못된 이유는 무엇입니까?

var a Abser
v := Vertex{1, 2}

a = v // invalid

내 이해는 이것이 괜찮을 것이라는 것입니다. v가 포인터 수신기를받는 Abs 함수를 "구현"하는 값 유형이지만 값으로도받을까요?

인터페이스 변수가 오른쪽에 담을 수있는 것에 대해 인터페이스가 더 엄격하게 설계 되었습니까? 인터페이스는 * Vertex와 Vertex를 두 가지 다른 유형으로보고 있지만 Abs () 메서드도 처리하는 데 문제가 없습니다.

답변

3 Marc Aug 20 2020 at 12:32

두 경우 모두 Go는 메서드를 실행할 포인터를 원합니다. 가장 큰 차이점은 메서드 호출은 자동으로의 주소를 가져 v오지만 인터페이스를 구현하는지 여부를 확인하는 것은 그렇지 않다는 것입니다.

메서드 호출 :

일반 유형에서 포인터 수신기로 메서드를 호출 할 때 Go는 허용되는 경우 자동으로 주소를 가져옵니다. 메서드 호출에 대한 사양에서 (강조 표시는 내 것임) :

xm () 메서드 호출은 x의 메서드 집합에 m이 포함되어 있고 인수 목록이 m의 매개 변수 목록에 할당 될 수있는 경우 유효합니다. x가 주소 지정이 가능하고 & x의 메소드 세트에 m이 포함 된 경우 xm ()은 (& x) .m ()의 약어입니다.

이 경우 x변수를 참조 v하고 주소를 지정할 수 있습니다. 따라서 메서드 호출에서 Go는 자동으로 (&v).Abs().

할당:

할당을 시도 할 때 a = v채워야하는 검사는 T is an interface type and x implements T.입니다. 메소드 세트 가 인터페이스와 일치하는 경우에만 v구현 Abser됩니다 . 이 메소드 세트는 다음과 같이 결정됩니다.

다른 유형 T의 메소드 세트는 수신자 유형 T로 선언 된 모든 메소드로 구성됩니다 . 해당 포인터 유형 * T의 메소드 세트는 수신자 * T 또는 T로 선언 된 모든 메소드 세트입니다 (즉, T의 메소드 세트도 포함합니다).

메소드 세트를 계산할 때 Go는 v메소드 호출에서 와 같이 주소를 사용하지 않습니다 . 이는에 대해 설정된 메서드 var v Vertex가 비어있어 인터페이스를 구현하지 못했음을 의미합니다 .

해결책:

이 문제를 해결하는 방법은 v자신 의 주소를 가져 오는 것입니다.

var a Abser
v := Vertex{1, 2}

a = &v

이렇게 하여 인터페이스를 *Vertex포함 Abs() float64하고 구현하는 메소드 세트를 확인 합니다 Abser.