인터페이스

인터페이스

인터페이스에 대해 알아보자.


메소드의 집합 인터페이스


프로그램을 확장하다 보면 기능이 추가될 수 있습니다. 그리고 다양한 구조체들과 그에 따른 ‘기능들이 추가되면 어떻게 될 것 같습니까?’ 어떤 객체에 어떤 메소드를 사용해야 하는지 굉장히 헷갈리게 될 것입니다. 따라서 변수를 묶은 구조체만 필요한 것이 아니라, 메소드를 모아놓은 '인터페이스'도 필요합니다.
인터페이스메소드들의 집합체로서 같은 속성의 기능을 하는 메소드들을 한눈에 보기 편하다는 점이 있습니다. 기능은 같지만 두 구조체의 필드가 다르고 연산 방법도 다르기 때문에 메소드도 두 개를 선언해야합니다. 따라서 이름은 같지만 내용물이 다른 메소드를 만들어야합니다.

package main

import (
	"fmt"
	"math"
)

type geometry interface { //인터페이스 선언 Reat와 Circle 메도스의 area를 모두 포함
	area() float64
}

type Rect struct {
	width, height float64
}

type Circle struct {
	radius float64
}

func (r Rect) area() float64 {
	return r.width * r.height
}

func (c Circle) area() float64 {
	return math.Pi * c.radius * c.radius
}


func main() {
	r1 := Rect{10, 20}
	c1 := Circle{10}
	r2 := Rect{12, 14}
	c2 := Circle{5}

	printMeasure(r1, c1, r2, c2)
}

func printMeasure(m ...geometry) { //인터페이스를 가변 인자로 하는 함수
	for _, val := range m { //가변 인자 함수의 값은 슬라이스형
		fmt.Println(val.area()) //인터페이스의 메소드 호출
	}
}

위 코드에서 인터페이스는 매개변수로 선언이 되어 따로 선언하지 않았습니다. 매개변수로 인터페이스를 사용한다는 것은 구조체에 관계없이 인터페이스에 포함된 메소드를 사용하겠다는 뜻입니다.

빈 인터페이스(Empty Interface)


구조체도 형을 사용자 정의로 사용하는 것이고 함수도 특별한 것이 아니라 형으로 사용할 수 있다고 했습니다. 인터페이스도 마찬가지입니다. 빈 인터페이스에 대해 알아보기 위해 몇 가지 특징을 알아보겠습니다.

1. 인터페이스는 내용을 따로 선언하지 않아도 형으로서 사용할 수 있습니다.
2. 인터페이스는 하나의 형이기 때문에 매개변수로 사용될 수 있습니다.
3. 인터페이스는 어떠한 타입도 담을 수 있는 컨테이너입니다. 즉 'Dynamic type'입니다.

예를 들어 어떤 변수에 순서대로 string형을 저장해 출력하고 int형을 저장해 출력한다고 생각해봅시다. 형이 다르기 때문에 다른 매개변수형을 가지는 함수를 만들고, 형이 달라짐에 따라 변수도 새롭게 초기화해야 합니다.
하지만 빈 인터페이스 형을 쓰면 어떠한 형도 담을 수 있어 편하게 사용할 수 있습니다.

package main
 
import "fmt"
 
func printVal(i interface{}) {
    fmt.Println(i)
}

func main() {
    var x interface{} //빈 인터페이스 선언
 
	x = 1
	printVal(x)
  
	x = "test"
    printVal(x)
}

위 예시에서는 간단한 코드의 형태로 사용해봤지만 앞으로 Go언어를 접하면 빈 인터페이스를 많이 볼 수 있을 것입니다. 이는 다양한 형을 담기 위한 Dynamic type이라는 것을 잘 알아두기 바랍니다.

Type Assertion


Assertion은 ‘주장’이라는 뜻입니다. 인터페이스형으로 선언된 변수는 초기화하는 값에 따라 형이 자동 명시되지만 사실 위에서 언급했다시피 Danamic type입니다. 따라서 확실한 형을 표현하기 위해서 'Type Assertion'을 할 필요가 있습니다. 인터페이스 형에서 형을 선언하기 위해서는 "변수이름.(형)"을 명시하면 됩니다. 주의해야할 점인터페이스 형으로 선언됐는데 nil 값인 경우 에러가 발생합니다.

package main

import "fmt"

func main() {
    var num interface{} = 10
 
    a := num       
    b := num.(int)
 
	fmt.Printf("%T,%d\n",a,a)
    printtest(b)
}

func printtest (i interface{}){
	fmt.Printf("%T,%d\n",i,i)
}

© 2022. All rights reserved. 신동민의 블로그