Go 언어에서 interface
타입을 정의할 때 구체적인 동작을 구현할 메소드의 집합을 나열하는 방식으로 표현한다. 어떤 타입이 특정한 interface를 따르기 위해서는, 그 interface에서 정의한 모든 method를 구현해야 한다. 간단히 말해 interface란 abstrct type으로, 정의할 타입이 어떤 interface의 인스턴스가 되기 위해 반드시 구현해야 할 함수들을 정의한 것이다. 이렇게 모든 method를 구현했다면 그 타입은 해당 interface를 satisfy한다고 표현한다.
interface의 가장 큰 장점은, 함수의 매개변수 타입을 interface로 정의했을 때 그 interface를 구현한 변수라면 어떤 것도 그 함수에 전달할 수 있다는 점이다. interface는 특별한 기능을 직접 제공하지 않고 단지 형식을 맞추는 역할만 한다.
type Shape interface {
area() float64
perimeter() float64
}
type Rect struct {
width float64
height float64
}
func (r Rect) area() float64 {
return r.width * r.height
}
func (r Rect) perimeter() float64 {
return 2 * (r.width + r.height)
}
type Circle struct {
radius float64
}
func (c Circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func showArea(shape Shape) {
fmt.Println(shape.area())
}
r := Rect{10., 20.}
c := Circle{10}
showArea(r)
// 반면 다음과 같이 사용은 할 수 없다.
// 이유는 Circle은 perimeter()를 구현하지 않았기 때문에 Shape의 instance가 될 수 없다.
showArea(c)
Go 프로그래밍을 하다보면 흔히 빈 인터페이스(empty interface)를 자주 접하게 되는데, 흔히 interface type이라 부른다.
여러 표준패키지들의 함수 Prototype을 살펴보면, 아래와 같이 빈 interface가 자주 등장함을 볼 수 있다.
빈 interface는 interface{} 와 같이 표현한다.
Go의 모든 Type은 적어도 0개의 메소드를 구현하고 있으므로 interface{}는 모든 타입을 표현할 수 있다.
즉 다음 코드의 Println은 모든 Type을 매개변수로 받을 수 있다.
type any = interface{}
...
func Println(a ...any) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
Type assersion
이란 x.(T) 형식의 표기법으로, x는 인터페이스 타입을, T는 구체적인 타입을 지정한다. 이 때 x에 실제로 저장되는 값의 타입은 T이며, T는 반드시 x의 인터페이스 타입을 충족해야 한다.
Type assersion으로 할 수 있는 일은 두 가지가 있다.
func main() {
var myInt interface{} = 123
k, ok := myInt.(int)
if ok {
fmt.Println("Success:", k)
}
v, ok := myInt.(float64)
if ok {
fmt.Println(v)
} else {
fmt.Println("Failed without panicking!")
}
}