go 인터페이스 주의점

3275 단어 go
하나의 대상을interface에 값을 부여할 때 무슨 일이 일어났는지 생각해 봅시다. 대상 변수와 인터페이스 변수는 같은 메모리 주소를 인용하는 것입니까?
go interface의 본질이 무엇인지에 대해 인터넷에서 두 개의 바늘을 가진 struct라고 하는데 하나는 실행할 때의 유형을 가리키고 하나는 대상을 가리키는 자체이다
나는 개인적으로 이 견해가 너무 모호하다고 느낀다. 그래도 실제 코드 실험을 하는 것이 좋겠다
type IObject interface {
	SetValue(value int)
	GetValue() int
}
type Object struct {
	Value int
}
func (obj Object) SetValue(value int) {
	obj.Value = value
}
func (obj Object) GetValue() int {
	return obj.Value
}
func main() {
	var obj = Object{Value: 1}
	var iObj IObject = obj        // * *
	obj.Value = 2 //   receiver  ,   obj.SetValue(2)  
	fmt.Println(obj.GetValue())    // "2":  
	fmt.Println(iObj.GetValue())    // "1":  
}

관건적인 조작 * 대상이 인터페이스에 값을 부여하는 것 * 이 실제적으로 값을 복사한 것은 Object 대상 변수 간의 값을 부여하는 효과와 같다는 결론을 얻을 수 있다
생각보다 자바처럼 인터페이스가 대상의 인용이 아니다
만약 이런 효과가 필요하다면, Object 대상의 바늘을 인터페이스에 값을 부여해야 한다
방금 코드를 직접 수정하여 값 부여 문장을 바늘로 값 부여하면 됩니다. 이때 IObject 변수가 값 부여된 것은 Object 대상의 바늘입니다.
type IObject interface {
	SetValue(value int)
	GetValue() int
}
type Object struct {
	Value int
}
func (obj Object) SetValue(value int) {
	obj.Value = value
}
func (obj Object) GetValue() int {
	return obj.Value
}
func main() {
	var obj = Object{Value: 1}
	var iObj IObject = &obj        // * *,  ,  
	obj.Value = 2
	fmt.Println(obj.GetValue())    // "2":  
	fmt.Println(iObj.GetValue())    // "2":  
	iObj.SetValue(3)      //  :  SetValue ,  receiver 
	fmt.Println(obj.GetValue())    // "2": 
	fmt.Println(iObj.GetValue())    // "2":
}



또한 주의해야 할 점이 있다. Go는 C++의 바늘 연산자가 없기 때문에 go 언어에서 바늘 연산자를 수치 연산자로 대체했다. 즉, 변수가 대상 자체든 대상의 바늘이든 모두 수치 연산자를 사용했기 때문에 이것은 어떤 영향을 미칠까?C++의 프로그래머로서 곤란함을 느낄 수 있습니다. 현재 저는 두 가지를 정리했습니다.
1. 모든 구성원을 뽑는 작업은 일괄적으로 처리된다. 이것도 기본이다. 변수가 대상이든 지침이든 직접 구성원을 뽑는 조작부호로 접근할 수 있다. 구성원은 필드와 방법을 포함한다.
2. 모든 부치와 전참의 부분은 민감한 처리를 필요로 한다. 바늘부호 바늘, 대상부호 대상, 바늘이 대상에게 부치려면 내용을 취해야 한다(C++와 같고 * 연산자), 대상이 바늘에 부치면 주소를 취해야 한다(C++와 같고 & 연산자), 함수 전참도 마찬가지로 이 규칙을 따라야 한다.
그럼 곰곰이 생각해 보세요. Receiver가 뭔데 어느 쪽을 따를까요?
시험을 통해receiver는 첫 번째 조항을 따랐는데 함수 전참이 아니라 코드를 올렸습니다.
type IObject interface {
	PrintValue()
}

type Object struct {
	Value int
}

func (obj Object) PrintValue() {    //  :   receiver  
	fmt.Println(obj.Value)
}
func main() {
	var obj = Object{Value: 5}
	var iObj1 IObject = obj        // Object   IObjedct
	iObj1.PrintValue()
	var iObj2 IObject = &obj  //  : Object    IObject,  
	iObj2.PrintValue()
}

신기한 점: Object의 바늘도 IObject일 수 있습니다. 첫 번째 규칙을 따르기 때문에 Object 바늘 호출 방법인 PrintValue도 값을 얻는 조작부호를 사용하지만, 이 값을 부여할 때 바늘이 값을 부여하는 것이지 대상이 값을 부여하는 것이 아닙니다.
그래서 우리는 대상receiver의 방식으로 하나의 인터페이스를 실현하면 이 대상의 변수와 대상 바늘의 변수는 모두 이 인터페이스에 값을 부여할 수 있다고 말할 수 있다.
그러나receiver가 명확한 대상의 바늘이라면 대상의 바늘이 인터페이스에 값을 부여하는 것만 말할 수 있고 대상이 인터페이스에 값을 부여하는 것은 말할 수 없다
type IObject interface {
	PrintValue()
}

type Object struct {
	Value int
}

func (obj *Object) PrintValue() {    //   receiver    
	fmt.Println(obj.Value)
}
func main() {
	var obj = Object{Value: 5}
	var iObj1 IObject = obj        //  
	iObj1.PrintValue()
	var iObj2 IObject = &obj
	iObj2.PrintValue()
}

다음 작은 결론:receiver는 가능한 한 바늘을 사용하고 인터페이스에 값을 부여할 때도 대상 바늘을 사용한다.

좋은 웹페이지 즐겨찾기