Go 언어

본문 바로가기
사이트 내 전체검색


Go 언어
Go 언어

3. 빈 인터페이스 사용하기

페이지 정보

작성자 관리자 댓글 0건 조회 864회 작성일 21-07-20 13:48

본문

3. 빈 인터페이스 사용하기

인터페이스에 아무 메서드도 정의되어 있지 않으면 모든 타입을 저장할 수 있습니다.


func f1(arg interface{}) { // 모든 타입을 저장할 수 있음

}

함수의 매개변수를 arg interface{}처럼 지정하여 빈 인터페이이스를 받도록 하였습니다.


다음과 같이 빈 인터페이스는 Any로 표현할 수 있습니다.


type Any interface{} // 인터페이스에 메서드를 지정하지 않음


func f2(arg Any) {   // 모든 타입을 저장할 수 있음

}

빈 인터페이스 타입은 함수의 매개변수, 리턴값, 구조체의 필드로 사용할 수 있습니다.


이제 모든 타입을 받아서 내용을 출력하는 함수를 만들어보겠습니다.


package main


import (

"fmt"

"strconv"

)


//                      ↓ 빈 인터페이스를 사용하여 모든 타입을 받음

func formatString(arg interface{}) string {

//       ↓ 인터페이스에 저장된 타입에 따라 case 실행

switch arg.(type) {

case int:                      // arg가 int형이라면

i := arg.(int)         // int형으로 값을 가져옴

return strconv.Itoa(i) // strconv.Itoa 함수를 사용하여 i를 문자열로 변환

case float32:                  // arg가 float32형이라면

f := arg.(float32)     // float32형으로 값을 가져옴

return strconv.FormatFloat(float64(f), 'f', -1, 32)

                                       // strconv.FormatFloat 함수를 사용하여 f를 문자열로 변환

case float64:                  // arg가 float64형이라면

f := arg.(float64)     // float64형으로 값을 가져옴

return strconv.FormatFloat(f, 'f', -1, 64)

                                       // strconv.FormatFloat 함수를 사용하여 f를 문자열로 변환

case string:                   // arg가 string이라면

s := arg.(string)      // string으로 값을 가져옴

return s               // string이므로 그대로 리턴

default:

return "Error"

}

}


func main() {

fmt.Println(formatString(1))

fmt.Println(formatString(2.5))

fmt.Println(formatString("Hello, world!"))

}

실행 결과

[jklee@www interface_test]$ go run main.go

1

2.5

Hello, world!

[jklee@www interface_test]$




formatString 함수의 매개변수를 보면 타입을 interface{}로 지정하였습니다. 

이렇게 하면 모든 타입을 처리할 수 있습니다. 

* 인터페이스에 저장된 타입을 알아내려면 switch 분기문 안에서 arg.(type)처럼 인터페이스 변수에 .(type)을 사용합니다. 

단 이 방법은 switch 분기문 안에서만 사용할 수 있고, 일반적인 방법으로는 사용할 수 없습니다. 

* 타입에 따라 case로 나눕니다. 

* 빈 인터페이스 변수는 그대로 사용할 수 없으므로 arg.(int), arg.(float32), arg.(float64), arg.(string)처럼 타입을 지정하여 값을 가져옵니다. 

이렇게 타입을 원하는 형태로 바꾸는 작업을 Type assertion이라고 합니다. 

* 각 타입에 맞게 strconv.Itoa, strconv.FormatFloat 함수를 사용하여 값을 문자열로 만듭니다. 

string의 값은 문자열이므로 변환하지 않고 그대로 리턴합니다.


일반 자료형뿐만 아니라 구조체 인스턴스 및 포인터도 빈 인터페이스로 넘길 수 있습니다.


package main


import (

"fmt"

"strconv"

)


type Person struct { // Person 구조체 정의

name string

age  int

}


func formatString(arg interface{}) string {

switch arg.(type) {

case Person:               // arg의 타입이 Person이라면

p := arg.(Person)  // Person 타입으로 값을 가져옴

return p.name + " " + strconv.Itoa(p.age) // 각 필드를 합쳐서 리턴

case *Person:              // arg의 타입이 Person 포인터라면

p := arg.(*Person) // *Person 타입으로 값을 가져옴

return p.name + " " + strconv.Itoa(p.age) // 각 필드를 합쳐서 리턴

default:

return "Error"

}

}


func main() {

fmt.Println(formatString(Person{"Maria", 20}))

fmt.Println(formatString(&Person{"John", 12}))


var andrew = new(Person)

andrew.name = "Andrew"

andrew.age = 35


fmt.Println(formatString(andrew))

}

실행 결과

Maria 20

John 12

Andrew 35


switch arg.(type) { }으로 인터페이스에 저장된 타입을 알아낸 뒤 각 구조체 타입별로 case를 만들어 처리합니다. 

여기서 구조체를 그대로 넘겨줬다면 case Person:으로 처리하고, 구조체의 포인터를 넘겨줬다면 case *Person:으로 처리합니다. 

마찬가지로 구조체일 때는 arg.(Person), 포인터일 때는 arg.(*Person)으로 값을 가져옵니다.


인터페이스에 저장된 타입이 특정 타입인지 검사하려면 다음과 같이 사용합니다.


var t interface{}

t = Person{"Maria", 20}


if v, ok := t.(Person); ok {

fmt.Println(v, ok)

}

실행 결과

{Maria 20} true


인터페이스.(타입) 형식입니다. 

첫 번째 리턴값은 해당 타입으로 된 값이며 두 번째 리턴값은 타입이 맞는지 여부입니다. 

타입이 일치하면 true 그렇지 않으면 false입니다.


댓글목록

등록된 댓글이 없습니다.


개인정보취급방침 서비스이용약관 모바일 버전으로 보기 상단으로

TEL. 063-469-4551 FAX. 063-469-4560 전북 군산시 대학로 558
군산대학교 컴퓨터정보공학과

Copyright © www.leelab.co.kr. All rights reserved.