Golang의interface 인터페이스 전면 이해

6836 단어

인터페이스


 
 
대상을 대상으로 프로그래밍을 할 때'인터페이스가 대상의 행위를 정의했다'고 할 수 있다. 그러면 구체적인 실현 행위는 대상에 달려 있다.
Go에서 인터페이스는 하나의 방법 서명입니다. (성명은 하나의 방법의 집합입니다.)하나의 유형이 인터페이스의 모든 방법에 대해 정의를 제공할 때, 이를 실현하는 인터페이스라고 부른다.그것은 oop과 매우 비슷하다.인터페이스에서 유형을 지정하는 방법은 유형이 어떻게 이런 방법을 실현하는지 결정한다.
 
이 예를 살펴보자. Animal 유형은 하나의 인터페이스이다. 우리는 Animal를 말할 수 있는 모든 것으로 정의할 것이다.이것은 Go 유형 시스템의 핵심 개념이다. 우리는 유형에 따라 실행할 수 있는 조작이 수용할 수 있는 데이터 유형이 아니라 추상적인 조작을 설계한다.
type Animal interface {
    Speak() string
}

  
매우 간단하다: 우리가 정의한AnimalSpeak 방법의 유형.Speak 방법은 매개 변수가 없고 문자열을 되돌려줍니다.
이 방법을 정의한 모든 유형은 Animal 인터페이스를 실현했다고 합니다.Go에 없어요.implements 키워드는 한 유형이 하나의 인터페이스를 실현했는지 판단하는 것이 완전히 자동적이다.이 인터페이스를 구현하는 몇 가지 유형을 만들겠습니다.
type Dog struct {
}

func (d Dog) Speak() string {
    return "Woof!"
}

type Cat struct {
}

func (c Cat) Speak() string {
    return "Meow!"
}

type Llama struct {
}

func (l Llama) Speak() string {
    return "?????"
}

type JavaProgrammer struct {
}

func (j JavaProgrammer) Speak() string {
    return "Design patterns!"
}

우리는 현재 네 종류의 다른 종류의 동물이 있다.DogCatLlamaJavaProgrammer .우리main 함수에서 우리는 하나를 만들었다[]Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}, 동물마다 무슨 말을 하는지 보자.
 
func main() {
    animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}
    for _, animal := range animals {
        fmt.Println(animal.Speak())
    }
}

  

interface {} 유형


  interface{}유형,
빈 인터페이스는 많은 혼동을 야기하는 근원이다.interface{} 유형은 방법이 없는 인터페이스입니다.없다implements 키워드, 그래서 모든 유형이 적어도 0가지 방법을 실현했기 때문에
모든 유형이 빈 인터페이스를 실현했다.이것은 함수를 작성하면interface{} 값을 매개 변수로 하면 이 함수에 어떤 값도 제공할 수 있습니다.예를 들면 다음과 같습니다.
func DoSomething(v interface{}) {
   // ...
}

  
이곳은 사람을 곤혹스럽게 하는 곳이다.DoSomething 함수 내부,v의 유형은 무엇입니까?
초보자들은 v 임의의 유형이라고 생각하지만, 이것은 잘못된 것이다.v 임의의 유형이 아니라 interface{} 유형입니다.맞아, 맞아!값을DoSomething 함수의 경우 Go가 실행될 때 유형 변환(필요한 경우)을 실행하고 값을 로 변환합니다.interface{} 유형의 값입니다.모든 값은 실행할 때 한 종류만 있고v의 정적 유형은interface{} .
이것은 당신을 의심하게 할 수 있습니다: 그래, 만약 전환이 발생한다면 도대체 어떤 물건이 함수로 들어왔는지interface{}의 값은?(구체적으로는 전례대로 말하면[]Animal에 저장된 것은 무엇입니까?)
 
하나의 인터페이스 값은 두 글자(32비트 기계 한 글자는 32bits, 64비트 기계 한 글자는 64bits)로 구성된다.한 글자는 이 값의 밑바닥 형식을 가리키는 방법표에 사용되고, 다른 한 글자는 실제 데이터를 가리키는 데 사용된다.나는 이것에 대해 끝없이 이야기하고 싶지 않다.
 
위의 예에서 우리가 변수animals를 초기화할 때 우리는 이렇게 Animal(Dog{})할 필요가 없다. 왜냐하면 이것은 자동이기 때문이다.이 원소들은 모두 Animal 유형이지만 그들의 밑바닥 유형은 다르다.
왜 이게 중요합니까?인터페이스가 메모리에서 어떻게 표시되는지 이해하면 잠재적인 곤혹스러운 일들을 분명하게 할 수 있다.예를 들어, "내가 []T를 []interface {}로 바꿀 수 있습니까?"이런 문제는 대답하기 쉽다.다음은 몇 가지 썩은 코드의 예로 interface{} 유형에 대한 흔한 오해를 나타낸다.
package main

import (
    "fmt"
)

func PrintAll(vals []interface{}) {
    for _, val := range vals {
        fmt.Println(val)
    }
}

func main() {
    names := []string{"stanley", "david", "oscar"}
    PrintAll(names)
}

  
이 코드를 실행하면 다음과 같은 오류가 발생합니다. cannot use names (type []string) as type []interface {} in argument to PrintAll정상적으로 작동하려면 []string[]interface{}로 변경해야 합니다.
 
package main

import (
    "fmt"
)

func PrintAll(vals []interface{}) {
    for _, val := range vals {
        fmt.Println(val)
    }
} func main() { names := []string{"stanley", "david", "oscar"} vals := make([]interface{}, len(names)) for i, v := range names { vals[i] = v } PrintAll(vals) }

  
추하지만 삶은 이렇다. 완벽한 일은 없다.(사실 이런 일은 자주 일어나지 않는다. []interface{} 네가 상상한 것처럼 그렇게 유용하지 않기 때문이다)
 

포인터 및 커넥터


 
인터페이스의 또 다른 미묘한 점은 인터페이스 정의가 하나의 실현자가 바늘 수신기나 값 수신기를 사용하여 인터페이스를 실현해야 하는지를 규정하지 않았다는 것이다.인터페이스 값을 정할 때, 밑바닥 형식이 바늘인지 아닌지를 보장할 수 없습니다.앞의 예시에서, 우리는 방법을 값 수신자 위에 정의할 것이다.우리 조금만 바꿔봅시다.CatSpeak() 포인터 수신기로 변경:
 
func (c *Cat) Speak() string {
    return "Meow!"
}

  
위 코드를 실행하면 다음과 같은 오류가 발생합니다.
cannot use Cat literal (type Cat) as type Animal in array or slice literal:
    Cat does not implement Animal (Speak method has pointer receiver)

  
이 오류는 CatAnimal 로 바꾸려고 시도했지만 *Cat 형식만 이 인터페이스를 실현했다는 뜻이다.이 오류를 복구하기 위해 바늘 new(Cat) 이나 &Cat{} 을 전송할 수 있습니다.
animals := []Animal{Dog{}, new(Cat), Llama{}, JavaProgrammer{}}

 
우리는 상반된 일을 하자. 우리는 *Dog 지침을 전달했지만 Dog 방법을 바꾸지 않았다.
animals := []Animal{new(Dog), new(Cat), Llama{}, JavaProgrammer{}}

  
이런 방식은 정상적으로 작동할 수 있다. 왜냐하면 하나의 바늘 유형은 그와 관련된 값 유형을 통해 값 유형을 묻는 방법을 방문할 수 있지만 반대로 안 된다.즉, Speak() 유형의 값은 *Dog 유형에 정의된 Dog 방법을 사용할 수 있고, Speak() 유형의 값은 Cat 유형에 정의된 방법에 접근할 수 없다.
이것은 신비롭게 들릴 수도 있지만, 다음 내용을 기억할 때 알 수 있다. Go의 모든 것은 값에 따라 전달된다.함수를 호출할 때마다 전송된 데이터가 복사됩니다.값 수신자가 있는 방법은 이 방법을 호출할 때 이 값을 복사합니다.예를 들면 다음과 같습니다.
func (t T)MyMethod(s string) {
    // ...
} 
*Cat 유형의 방법입니다.방법 수신기는 다른 매개 변수처럼 값을 통해 함수에 전달된다.
모든 매개 변수는 값을 통해 전달되기 때문에 왜func(T, string)방법으로는*Cat 유형의 값이 호출되었습니다.어느Cat 유형의 값이 많을 수 있음Cat 유형의 바늘이 그것을 가리키는데 만약 우리가 통과하려고 한다면*Cat 유형의 값으로 호출Cat의 방법은 어떤 지침에 대응하는지 전혀 모른다.하면, 만약, 만약...*Cat 유형에 하나의 방법이 있는데,Dog 이 방법을 사용하면 이 바늘에 대응하는 것을 정확하게 찾을 수 있다.*Dog 유형의 값을 위의 방법으로 호출합니다.실행할 때 Go가 자동으로 도와주기 때문에 우리는 C 언어에서처럼 다음과 같은 문장을 사용할 필요가 없다Gog .

결어


 
나는 이 글을 다 읽은 후에 네가 Go의 인터페이스를 더욱 적절하게 사용할 수 있기를 바란다. 아래의 결론을 기억해라.
  • 데이터 유형 간의 동일한 기능을 고려하여 같은 필드가 아닌 추상적인 필드를 만듭니다
  • .
  • d->Speak()의 값은 임의의 유형이 아니라 interface{}유형
  • 이다.
  • 인터페이스는 두 글자의 크기를 포함하고 interface{}
  • 와 유사하다
  • 함수는 (type, value)를 매개 변수로 받아들일 수 있지만 되돌아오지 않는 것이 좋다interface{}
  • 바늘 유형은 가리키는 값을 호출할 수 있지만 반대로 사용할 수 없다
  • 함수 중의 매개 변수 심지어 수용자는 모두 값을 통해 전달된다
  • 한 인터페이스의 값은 바로 인터페이스일 뿐 바늘과 아무런 관계가 없다
  • 바늘이 가리키는 값을 방법에서 수정하려면 interface{} 조작부호
  • 를 사용하십시오
     
    전재 대상:https://www.cnblogs.com/echojson/p/10746807.html

    좋은 웹페이지 즐겨찾기