Go 퀴즈 Advent Calendar 2010/12/16 (wed)

11381 단어 Gotech
이 글은 Go 퀴즈 Advent Calendar 2020 16일째 되는 글이다.

문제.


https://play.golang.org/p/v7M1kD3qEGJ
package main

import "fmt"

type T struct {
	x int
}

func (t T) Get() int {
	return t.x
}
func (t T) Set(x int) T {
	t.x = x
	return t
}
func (t *T) Add(x int) *T {
	t.x += x
	return t
}
func main() {
	var t T
	fmt.Println(t.Set(1).Add(1).Get())
}

옵션

  • build(compile) error
  • panic
  • 1
  • 로 표시
  • 2
  • 로 표시

    생각해봐!


      _____        _                                               
     | ____|_ __  (_) ___  _   _                                   
     |  _| | '_ \ | |/ _ \| | | |                                  
     | |___| | | || | (_) | |_| |                                  
     |_____|_| |_|/ |\___/ \__, |                                  
                |__/    _  |___/                                   
      ___  ___ | |_   _(_)_ __   __ _                              
     / __|/ _ \| \ \ / / | '_ \ / _` |                             
     \__ \ (_) | |\ V /| | | | | (_| |                             
     |___/\___/|_| \_/ |_|_| |_|\__, |                             
       ____                     |___/     _                        
      / ___| ___         __ _ _   _(_)___| |                       
     | |  _ / _ \ _____ / _` | | | | |_  / |                       
     | |_| | (_) |_____| (_| | |_| | |/ /|_|                       
      \____|\___/       \__, |\__,_|_/___(_)                       
       __ _ _ __  _____    |_|____ _ __  (_)___                    
      / _` | '_ \/ __\ \ /\ / / _ \ '__| | / __|                   
     | (_| | | | \__ \\ V  V /  __/ |    | \__ \                   
      \__,_|_| |_|___/ \_/\_/ \___|_|    |_|___/                   
       __ _| |_  | |__   ___ | |_| |_ ___  _ __ ___                
      / _` | __| | '_ \ / _ \| __| __/ _ \| '_ ` _ \               
     | (_| | |_  | |_) | (_) | |_| || (_) | | | | | |              
      \__,_|\__| |_.__/ \___/ \__|\__\___/|_| |_| |_|     _      _ 
       ___  / _| | |_| |__ (_)___    __ _ _ __| |_(_) ___| | ___| |
      / _ \| |_  | __| '_ \| / __|  / _` | '__| __| |/ __| |/ _ \ |
     | (_) |  _| | |_| | | | \__ \ | (_| | |  | |_| | (__| |  __/_|
      \___/|_|    \__|_| |_|_|___/  \__,_|_|   \__|_|\___|_|\___(_)
    
    

    해설


    A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m():
  • 방법 호출x.m()은 x 유형의 방법 집합m을 포함하고 주어진 매개 변수 목록을 m의 매개 변수 목록에 대입할 수 있을 때 유효하다.
  • 만약에 x를 주소화할 수 있고 &x의 방법집은 m를 포함하고 x.m()&x.m()의 생략 표현이다.
  • 나는 이번 문제를 다시 한 번 말할 것이다.
    type T struct {
    	x int
    }
    
    func (t T) Get() int {
    	return t.x
    }
    func (t T) Set(x int) T {
    	t.x = x
    	return t
    }
    func (t *T) Add(x int) *T {
    	t.x += x
    	return t
    }
    func main() {
    	var t T
    	fmt.Println(t.Set(1).Add(1).Get())
    }
    
    그 중에서 다음과 같은 세 가지 방법이 호출되었다.
  • t.Set(1)
  • t.Set(1).Add(1)
  • t.Set(1).Add(1).Get()
  • 첫 번째t.Set(1)는 T형이고 T의 방법집에Set가 포함되어 있어 문제가 없습니다.물론 매개 변수의 대입 가능성도 만족시켰다.
    두 번째t.Set(1).Add(1)를 보면 t.Set(1)T형이기 때문에 방법팀에 호출 수신기 방법Add이 포함되지 않는다.그럼 t.Set(1)를 주소화한 후&t.Set(1)의 생략 표현인가요?이를 위해t.Set(1) 반드시 주소화할 수 있어야 한다.그럼 주소화 가능성을 살펴봅시다.
    출처:
    For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
    이에 따라addressable의 경우 아래 5개다.
  • 변수
  • pointer indirection*p
  • 입니다.
  • 는 영화에 대한 색인 연산의 결과
  • 주소 찾기 struct의 필드 선택기
  • 주소 지정 가능 어레이에 대한 인덱스 계산 결과
  • t.Set(1) 이 공식은 상기 어느 것에도 적용되지 않기 때문에 주소화할 수 없다. t.Set(1).Add(1) 이런 방법은 illegal로 호출된다.따라서 본 문제의 코드는 컴파일할 수 없으며 다음과 같은 오류 정보를 출력합니다.
    ./prog.go:22:22: cannot call pointer method on t.Set(1)
    ./prog.go:22:22: cannot take the address of t.Set(1)
    
    오류 메시지에는 해설 절차와 같은 내용이 적혀 있다.
    또한, Addrssability가 규격서에서 인용한 단락에 대한 마지막 문장은composite literal이addressble가 아니라는 것을 전제로 한다.'As an exception'은'address operator&에 적용되는 것은 addressable의 operand 원칙에만 해당한다'는 예외를 뜻하며,'composite literal은addressable& 적용은 아니지만'이라는 뜻이다.
    이것은 본 문제의 방법으로 아래의 코드를 쓰면 알 수 있다.playground 링크가 추가되었으니 확인하십시오.
    T{}.Add(1) // compile error. T{}がaddressableではないから。
    
  • Addressability
  • 설명 요약

  • Go의 방법 선언은value receiver와pointer receiver라는 두 가지 선언 방법이 있다.
  • 묘사
  • 에 편리하도록 value.PointerReceiverMethod()(&value).PointerReceiverMethod()로 해석한다.
  • 단, 이 기재 방법이 유효하기 위해서는 value를 주소화할 수 있어야 한다.주소화가 가능한 경우는 5개다.
  • 또한composite literals 추가&는 가능하지만 주소화는 불가능합니다.
  • 정답


    (1) 중 compile(build) error이 정답입니다.

    좋은 웹페이지 즐겨찾기