17.3. 프로그램언어 고(Go)의 인터페이스 형 변환

프로그램언어 고(Go)의 인터페이스 형 변환방법

프로그램언어 고(Go)에서 인터페이스 형 변환은 interface{} 형을 사용하여 형 변환을 할 수 있습니다.

interface{}는 빈 인터페이스로 어떤 형이든 할당할 수 있으며, 이를 사용하여 형 변환을 할 수 있습니다.

package main

import "fmt"

func main() {

    var i interface{}
    
    i = "hello"

    s := i.(string)
    fmt.Println(s)

    i = 5

    n := i.(int)
    fmt.Println(n)

}

위의 예제코드에서 보면 i 변수를 interface{} 형으로 선언하였습니다.

i에 string 형인 “hello”를 할당하고 i.(string)으로 string 형으로 형 변환을 하였습니다.

마찬가지로 i에 int 형인 5를 할당하고 i.(int)로 int 형으로 형 변환을 하였습니다.

이처럼 interface{} 형을 사용하면 어떤 형이든 할당이 가능하고, 형 단언(type assertion)을 사용하여 원하는 형으로 변환할 수 있습니다.

하지만 인터페이스 값의 실제 형을 모르면 런타임 에러가 발생할 수 있으므로 주의가 필요합니다.

프로그램언어 고(Go)에서의 인터페이스를 다른 형으로 변환하는 예제

프로그램언어 고(Go)에서 인터페이스를 다른 타입으로 변환하는 예제를 살펴보겠습니다.

예를 들어, 다음과 같은 인터페이스가 정의되어 있다고 합시다.

type Shape interface {
    Area() float64
}

type Circle struct {
    x, y, radius float64
}

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

여기서 Circle 구조체는 Shape 인터페이스를 구현하고 있습니다.

Circle 인스턴스를 Shape 형으로 변환하려면 다음과 같이 변환할 수 있습니다.

func printArea(shape Shape) {
    fmt.Println(shape.Area()) 
}

c := Circle{x: 0, y: 0, radius: 5}
printArea(&c)

printArea 함수는 Shape 인터페이스를 파라미터로 받기 때문에, Circle 포인터를 Shape으로 명시적 변환하지 않고 그대로 전달할 수 있습니다.

반대로 Shape을 Circle 타입으로 변환하려면 타입 단언(type assertion)을 사용할 수 있습니다.

func circleArea(shape Shape) float64 {
    c, ok := shape.(*Circle)
    if !ok {
        return 0 
    }
    return math.Pi * c.radius * c.radius
}

circleArea 함수는 Shape을 Circle 포인터로 변환하려고 시도합니다. 변환에 성공하면 ok 값이 true가 되고, 실패하면 false가 됩니다.

이와 같이 Go에서 인터페이스와 구조체 사이의 변환이 자유롭기 때문에, 추상화와 다형성을 모두 잘 지원할 수 있습니다.

프로그램언어 고(Go)에서의 형 변환을 사용한 다형성 구현 방법

프로그램언어 고(Go)에서는 인터페이스를 사용하여 다형성을 구현할 수 있습니다. 인터페이스를 정의하고, 그 인터페이스를 구현하는 구조체를 만들면, 그 구조체의 포인터나 값을 인터페이스 타입의 변수에 저장할 수 있습니다.

이러한 방식으로, 구조체의 실제 타입을 추상화하고 인터페이스 타입으로 통일할 수 있습니다. 이를 통해 다형성을 구현할 수 있습니다.

예를 들어 다음과 같은 인터페이스와 구조체를 정의할 수 있습니다.


type Shape interface {
    Area() float64
}

type Rectangle struct {
    Width, Height float64 
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

여기서 Shape 인터페이스는 Area 메서드를 가지고 있습니다. 이 인터페이스를 구현하는 Rectangle과 Circle 구조체를 정의했습니다.

그리고 이 구조체들은 각각 Area 메서드를 구현하고 있어 Shape 인터페이스를 만족시킵니다.

이제 Shape 인터페이스 타입의 변수를 선언하고, Rectangle과 Circle 구조체의 인스턴스를 이 변수에 할당할 수 있습니다.


var shapes []Shape
shapes = append(shapes, Rectangle{Width: 3, Height: 4}) 
shapes = append(shapes, Circle{Radius: 5})

for _, s := range shapes {
    fmt.Println(s.Area())
}

위와 같이 실제 타입을 인터페이스 타입으로 추상화하여, 동일한 인터페이스를 구현하는 다양한 구조체를 통일된 방식으로 다룰 수 있게 됩니다.

즉, 인터페이스와 구조체를 조합하여 형 변환을 통한 다형성을 가능하게 할 수 있습니다. 이를 통해 타입에 구애받지 않고 다형적인 프로그래밍이 가능해집니다.

프로그램언어 고(Go)에서의 인터페이스와 구체적인 타입 간의 형 변환

프로그램언어 고(Go)에서 인터페이스는 구체적인 타입을 추상화해서 표현한 타입입니다. 인터페이스에 정의된 메서드를 실제 구현하는 구체적인 타입은 그 인터페이스 타입으로 변환(형 변환)할 수 있습니다.

예를 들어 다음과 같은 인터페이스가 있다고 합시다.

type Reader interface {
    Read(b []byte) (n int, err error)
}

Reader 인터페이스는 Read 메서드를 정의하고 있습니다. 실제 이 인터페이스를 구현하는 구조체는 다음과 같습니다.

type File struct {
    // ...
}

func (f *File) Read(b []byte) (n int, err error) {
    // 구현 생략
}

File 구조체는 Reader 인터페이스에서 정의한 Read 메서드를 실제로 구현하고 있습니다.

따라서 *File 타입은 Reader 인터페이스 타입으로 변환할 수 있습니다.

var r Reader = &File{}

위 코드에서 보듯이 \*File 타입의 인스턴스를 Reader 인터페이스 타입의 변수에 할당할 수 있습니다. 즉, 형 변환이 가능함을 의미합니다.

이처럼 고(Go)에서는 인터페이스를 구현하는 구체적인 타입은 해당 인터페이스 타입으로 형 변환이 가능합니다. 이를 통해 구체적인 타입을 추상화하여 제네릭한 코드를 작성할 수 있습니다.

프로그램언어 고(Go)에서의 형 변환 하면서 발생한 에러 핸들링 방법


package main

import "fmt"

func main() {

    var i int = 10
    var f float64 = float64(i)
    fmt.Println(f)

}

고(Go)에서 형 변환을 할 때에는 위의 예제처럼 내장 함수를 사용하거나 특정 형을 명시적으로 캐스팅함으로써 형 변환이 가능합니다.

이 과정에서 발생할 수 있는 대표적인 에러는 다음과 같습니다.

1. 파생 불가능한 형 변환 시도
– 예를 들어 *int형을 string형으로 변환하려고 할 때 발생

2. 범위 밖 값의 형 변환 시도
– 예를 들어 int형의 최대값보다 큰 uint형 정수를 int형으로 캐스팅하려고 할 때 발생

이러한 에러가 발생했을 때의 대응 방법은 주로 다음과 같습니다.

1. 에러 처리
– 변환이 가능한지 미리 판단한 후 처리
– 변환 시 에러 발생 시 별도의 에러 처리 로직 구현

2. 명시적 확인
– 인터페이스 타입 어설션(type assertion)을 통해 형 변환 가능 여부 확인
– 타입 스위치 문법을 사용하여 가능한 형 확인

3. 기본값 설정
– 변환 시 0 또는 기본값 리턴되도록 처리

위 방법을 적용하여 형 변환에서 발생할 수 있는 예외를 처리할 수 있습니다.

필요 시 다음의 예제 코드를 참고하시기 바랍니다.


func convert(i interface{}) int {
    // 명시적 타입 검사
    switch v := i.(type) {
    case int:
        return v
    case float64:
        return int(v) 
    default:
        return 0 // 기본값 리턴
    }
}

func main() {
    var i int = 10
    fmt.Println(convert(i))

    var f float64 = 5.5
    fmt.Println(convert(f))  
}

위에서 언급한 내용이 도움이 되었기를 바랍니다. 형 변환과 관련된 추가 질문이 있으시다면 주저 말고 문의주세요. 친절하게 답변 드리겠습니다.

Leave a Comment