수색…


비고

Go의 인터페이스 는 고정 된 메소드 세트입니다. 유형은 인터페이스의 수퍼 세트 인 경우 메소드를 암시 적으로 구현합니다. 의도적 인 선언은 없습니다.

간단한 인터페이스

Go에서 인터페이스는 단지 일련의 메소드 일뿐입니다. 인터페이스를 사용하여 주어진 객체의 동작을 지정합니다.

type Painter interface {
    Paint()
}

구현 형은 그것이 인터페이스를 구현하고 있다고 선언 할 필요는 없다 . 동일한 서명의 메소드를 정의하는 것으로 충분합니다.

type Rembrandt struct{}

func (r Rembrandt) Paint() {
    // use a lot of canvas here 
}

이제 구조를 인터페이스로 사용할 수 있습니다.

var p Painter
p = Rembrandt{}

인터페이스는 임의의 수의 유형으로 충족 (또는 구현) 될 수 있습니다. 또한 유형은 임의의 수의 인터페이스를 구현할 수 있습니다.

type Singer interface {
     Sing()
}

type Writer interface {
     Write()
}

type Human struct{}

func (h *Human) Sing() {
    fmt.Println("singing")
}

func (h *Human) Write() {
    fmt.Println("writing")
}



type OnlySinger struct{}
func (o *OnlySinger) Sing() {
    fmt.Println("singing")
}

여기서 Human 구조체는 SingerWriter 인터페이스를 모두 만족하지만 OnlySinger 구조체는 Singer 인터페이스 만 만족합니다.


빈 인터페이스

메소드가없는 빈 인터페이스 유형이 있습니다. interface{} 로 선언합니다. 여기에는 메소드가 없으므로 모든 type 충족시킵니다. 따라서 빈 인터페이스는 모든 유형 값을 포함 할 수 있습니다.

var a interface{}
var i int = 5
s := "Hello world"

type StructType struct {
    i, j int
    k string
}


// all are valid statements
a = i
a = s
a = &StructType{1, 2, "hello"}

인터페이스의 가장 일반적인 사용 사례는 변수가 하나 이상의 동작을 지원하는지 확인하는 것입니다. 반대로 비어있는 인터페이스의 기본 사용 예는 구체적인 유형에 관계없이 모든 값을 포함 할 수있는 변수를 정의하는 것입니다.

이 값을 원래 유형으로 되돌리려면

i = a.(int)
s = a.(string)
m := a.(*StructType)

또는

i, ok := a.(int)
s, ok := a.(string)
m, ok := a.(*StructType)

okinterface a 가 주어진 유형으로 변환 가능한지 여부를 나타냅니다. ok 을 캐스팅 할 수 없으면 false 됩니다.


인터페이스 값

인터페이스의 변수를 선언하면 인터페이스에서 선언 한 메소드를 구현하는 모든 값 유형을 저장할 수 있습니다!

interface Singer h 를 선언하면 Human 또는 OnlySinger. 유형의 값을 저장할 수 있습니다 OnlySinger. 이는 Singer 인터페이스에서 지정한 메서드를 모두 구현한다는 사실 때문입니다.

var h Singer
h = &human{}

h.Sing()

인터페이스에서 기본 유형 결정

이동 중에 어떤 기본 유형을 전달했는지를 아는 것이 유용 할 때가 있습니다. 이것은 유형 전환으로 수행 할 수 있습니다. 여기에는 두 개의 구조체가 있다고 가정합니다.

type Rembrandt struct{}

func (r Rembrandt) Paint() {}

type Picasso struct{}

func (r Picasso) Paint() {}

Painter 인터페이스를 구현합니다.

type Painter interface {
    Paint()
}

그런 다음이 스위치를 사용하여 기본 유형을 결정할 수 있습니다.

func WhichPainter(painter Painter) {
    switch painter.(type) {
    case Rembrandt:
        fmt.Println("The underlying type is Rembrandt")
    case Picasso:
        fmt.Println("The underlying type is Picasso")
    default:
        fmt.Println("Unknown type")
    }
}

유형이 인터페이스를 만족하는지 컴파일 시간 확인

인터페이스 및 구현 (인터페이스를 구현하는 유형)은 "분리"됩니다. 따라서 유형이 인터페이스를 구현 하는지를 컴파일 타임에 확인하는 것은 정당한 질문입니다.

유형 확인하기 위해 컴파일러를 요구하는 한 가지 방법 T 인터페이스 구현 I 제로 가치 사용하여 할당을 시도하는 것입니다 T 또는 포인터 T 적절를. 불필요한 쓰레기를 피하기 위해 빈 식별자 에 할당 할 수도 있습니다.

type T struct{}

var _ I = T{}       // Verify that T implements I.
var _ I = (*T)(nil) // Verify that *T implements I.

T 또는 *TI 구현하지 않으면 컴파일 타임 오류가 발생합니다.

이 질문은 공식 FAQ에서도 나타납니다 : 형식이 인터페이스를 만족하도록하려면 어떻게해야합니까?

유형 스위치

유형 스위치를 사용하여 케이스의 유형과 일치하는 변수를 얻을 수도 있습니다.

func convint(v interface{}) (int,error) {
    switch u := v.(type) {
    case int:
        return u, nil
    case float64:
        return int(u), nil
    case string:
        return strconv(u)
    default:
        return 0, errors.New("Unsupported type")
    }
}

형식 어설 션

Type Assertion을 사용하여 인터페이스의 실제 데이터 유형에 액세스 할 수 있습니다.

interfaceVariable.(DataType)

인터페이스 Subber 를 구현하는 MyType 구조체의 예 :

package main

import (
    "fmt"
)

type Subber interface {
    Sub(a, b int) int
}

type MyType struct {
    Msg string
}
 
//Implement method Sub(a,b int) int
func (m *MyType) Sub(a, b int) int {
    m.Msg = "SUB!!!"

    return a - b;
}

func main() {
    var interfaceVar Subber = &MyType{}
    fmt.Println(interfaceVar.Sub(6,5))
    fmt.Println(interfaceVar.(*MyType).Msg)
}

.(*MyType) 이 없으면 Msg 필드에 액세스 할 수 없습니다. interfaceVar.Msg 실행하면 컴파일 오류가 표시됩니다.

interfaceVar.Msg undefined (type Subber has no field or method Msg)

수학적 측면에서 인터페이스로 이동

수학, 특히 Set Theory 에서 우리는 집합 (set )이라고 불리는 것들의 집합을 가지고 있으며, 그것들을 원소 로 명명 합니다 . A, B, C, ...와 같은 이름을 가진 세트를 보여줍니다. 또는 멤버를 중괄호 표기 {a, b, c, d, e}로 명시하여 명시 적으로 표시합니다. 우리가 임의의 원소 x와 세트 Z를 가지고 있다고 가정하자. 핵심 질문은 "x가 Z의 멤버인지 이해할 수 있는가?"입니다. 이 질문에 대한 수학자의 대답은 집합의 특성 속성 입니다. 특성 집합의 특성 은 집합을 완전히 기술하는 표현식입니다. 예를 들어 {0, 1, 2, 3, 4, 5, ...}의 자연수 가 있습니다. 이 집합을 다음 표현식으로 설명 할 수 있습니다. {a n | a 0 = 0, a n = a n-1 +1}이다. 마지막 표현식에서 a 0 = 0, a n = a n-1 +1은 자연수 집합의 특성입니다. 이식이 있다면 우리는이 집합을 완전히 만들 수 있습니다 . 이 방식으로 짝수 세트를 기술 해보자. 이 집합은 {0, 2, 4, 6, 8, 10, ...} 숫자로 만들어집니다. 한 눈으로 우리는 자연수의 특징 재산에 대한 몇 가지 추가 조건을 추가 할 경우이 숫자도 모두 즉 자연수 것으로 알고 있습니다, 우리는이 설정을 설명하는 새로운 표현을 구축 할 수 있습니다. 그래서이 표현으로 설명 할 수 있습니다 : {n | N은 자연수의 부재와 2 제로}의 N의 플랜이다. 이제 우리는 세트의 특성 특성을 얻고 원하는 요소를 필터링하여 우리 세트의 요소를 리턴하는 필터를 작성할 수 있습니다. 예를 들어 자연수 필터가있는 경우 자연수와 짝수 모두이 필터를 통과 할 수 있지만 짝수 필터가있는 경우 3과 137871과 같은 일부 요소는 필터를 전달할 수 없습니다.

Go의 인터페이스 정의는 특성을 정의하는 것과 같습니다. 인터페이스를 함수의 인수로 사용하는 메커니즘은 요소를 탐지하는 필터가 원하는 집합의 구성원인지 여부와 같습니다. 코드로이 부분을 설명 할 수 있습니다.

type Number interface {
    IsNumber() bool // the implementation filter "meysam" from 3.14, 2 and 3
}

type NaturalNumber interface {
    Number
    IsNaturalNumber() bool // the implementation filter 3.14 from 2 and 3
}

type EvenNumber interface {
    NaturalNumber
    IsEvenNumber() bool // the implementation filter 3 from 2
}

Number 의 고유 속성은 IsNumber 메서드가있는 모든 구조체이며 NaturalNumberIsNumberIsNaturalNumber 메서드를 모두 포함하고 EvenNumber 는 마지막으로 IsNumber , IsNaturalNumberIsEvenNumber 메서드가있는 모든 형식입니다. 이 인터페이스의 해석 덕분에 interface{} 에는 특성이 없으므로 모든 유형을 허용합니다 (값을 구별하기위한 필터가 없기 때문에).



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow