interface 타입
interface 타입은 인터페이스라고 불리는 메서드 집합(method set)을 명시한다. 주어진 인터페이스의 확대집합(superset)에 해당하는 메서드 집합을 갖고 있는 어떠한 타입의 값이든 interface 타입의 변수에 저장할 수 있다. 그러한 타입에 대해서는 인터페이스를 구현했다라고 말한다. 초기화되지 않은 interface 타입의 변수는 nil 값을 갖는다.
InterfaceType = "interface" "{" { MethodSpec ";" } "}" . MethodSpec = MethodName Signature | InterfaceTypeName . MethodName = identifier . InterfaceTypeName = TypeName .
모든 메서드 집합에서 그런 것 처럼, interface 타입내, 각 메서드는 blank 식별자(blank identifier)가 아닌 고유한 명칭을 가져야 한다.
// A simple File interface
interface {
Read(b Buffer) bool
Write(b Buffer) bool
Close()
}
한 인터페이스는 여러 타입으로 구현될 수도 있다. 예를 들어, 만약 타입 S1와 S2가 다음과 같은 메서드 집합을 가지고 있다면
func (p T) Read(b Buffer) bool { return … }
func (p T) Write(b Buffer) bool { return … }
func (p T) Close() { … }
(위에서 T는 S1일 수도 있고 S2일 수도 있다) 이들이 가지고 있거나 공유하고 있는 다른 메서드들과는 상관없이 S1과 S2는 File 인터페이스를 구현한 것이다.
타입은 자신의 메서드에 인터페이스의 메서드를 포함시키는 방법을 통해 어떠한 인터페이스든지 구현할 수 있기 때문에 여러 인터페이스를 함께 구현하는 것도 가능하다. 예를 들어, 모든 타입은 empty interface를 구현하고 있다:
interface{}
추가로, Locker라는 인터페이스를 정의한 타입 선언문내 열거되어 있는 인터페이스 사양을 보자.
type Locker interface {
Lock()
Unlock()
}
만약 S1과 S2가 아래의 메서드도 구현했다면
func (p T) Lock() { … }
func (p T) Unlock() { … }
이들은 File 인터페이스 뿐만 아니라 Locker 인터페이스도 구현한 것이다.
인터페이스 T는 메서드의 사양이 있어야 할 자리에 (경우에 따라서는 패키지 이름을 동반한) interface 타입 이름 E를 사용할 수도 있다. 이것을 T안에 인터페이스 E를 임베딩했다고 부른다; 임베딩은 (엑스포트 여부에 상관없이) E의 모든 메서드를 인터페이스 T에 추가한다.
type ReadWriter interface {
Read(b Buffer) bool
Write(b Buffer) bool
}
type File interface {
ReadWriter // ReadWriter의 메서드를 추가한 것과 같음
Locker // Locker의 메서드를 추가한 것과 같음
Close()
}
type LockedFile interface {
Locker
File // 허용안됨: Lock, Unlock이 고유하지 않음
Lock() // 허용안됨: Lock이 고유하지 않음
}
인터페이스 T는 자신을 임베딩할 수 없고 T를 임베딩한 다른 어떤 인터페이스 타입도 재귀적으로 임베딩할 수 없다.
// 허용안됨: Bad는 자신을 임베딩할 수 없음
type Bad interface {
Bad
}
// 허용안됨: Bad1은 Bad2를 이용해 임베딩할 수 없음
type Bad1 interface {
Bad2
}
type Bad2 interface {
Bad1
}