인터페이스를 처음 사용하고 github의 SOAP 요청을하려고합니다.
나는의 의미를 이해하지 못한다
Msg interface{}
이 코드에서 :
type Envelope struct {
Body `xml:"soap:"`
}
type Body struct {
Msg interface{}
}
나는 같은 구문을 관찰했다.
fmt.Println
그러나 무엇이 달성되고 있는지 이해하지 못한다
interface{}
답변
” Gos 에서 인터페이스를 사용하는 방법 “( ” Russ Cox의 인터페이스 설명 “을 기반으로) 기사를 참조 할 수 있습니다 .
무엇 이며 인터페이스는?
인터페이스는 두 가지입니다.
- 일련의 방법이며
- 그러나 그것은 또한 유형입니다
interface{}
유형은 빈 인터페이스는 아무런 방법이없는 인터페이스입니다.구현 키워드가 없기 때문에 모든 유형은 최소 0 개의 메소드를 구현하며 인터페이스 만족은 자동으로 수행 되므로 모든 유형은 빈 인터페이스를 충족합니다 .
즉,interface{}
값을 매개 변수로 사용 하는 함수를 작성하면 해당 함수에 임의의 값을 제공 할 수 있습니다 .
(그것은 Msg
당신의 질문에서 대표하는 것입니다 : 모든 가치)
func DoSomething(v interface{}) {
// ...
}
혼란스러운 부분은 다음과 같습니다.
DoSomething
함수 내부에서 유형 은 무엇v
입니까?초보자 고퍼들은“
v
모든 유형의” 것이라고 믿게 되지만 그것은 잘못입니다.
v
어떤 유형도 아닙니다. 그것은이다interface{}
유형 .에 값을 전달할 때
DoSomething
기능의 이동 런타임에서 수행 타입 변환 (필요할 경우), 및 내지 An 값을 변환interface{}
값 .
모든 값은 런타임시 정확히 하나의 유형을 가지며,v
하나의 정적 유형은interface{}
입니다.인터페이스 값은 두 단어의 데이터로 구성됩니다 .
- 한 단어는 값의 기본 유형에 대한 메소드 테이블을 가리키는 데 사용됩니다.
- 다른 단어는 해당 값이 보유한 실제 데이터를 가리키는 데 사용됩니다.
부록 : 인터페이스 구조에 관한 Russ의 기사는 다음과 같습니다.
type Stringer interface {
String() string
}
인터페이스 값은 인터페이스에 저장된 유형에 대한 정보를 가리키는 포인터와 관련 데이터를 가리키는 두 단어 쌍으로 표시됩니다.
Stringer 유형의 인터페이스 값에 b를 지정하면 인터페이스 값의 두 단어가 설정됩니다.
인터페이스 값의 첫 번째 단어는 내가 인터페이스 테이블 또는 itable이라고 부르는 것을 가리 킵니다 (i-table로 발음됩니다. 런타임 소스에서 C 구현 이름은 Itab입니다).
itable은 관련된 유형에 대한 일부 메타 데이터로 시작한 다음 함수 포인터 목록이됩니다.
itable은 dynamic type이 아닌 인터페이스 유형에 해당합니다 .
이 예에서는Stringer
Binary 유형 을 보유 할 수있는 Stringer를 만족시키는 데 사용되는 메소드를 나열합니다String
. Binary의 다른 메소드 (Get
)는에 나타나지 않습니다itable
.인터페이스 값의 두 번째 단어는 실제 데이터 ( 이 경우 사본)를 가리 킵니다
b
.
할당은var s Stringer = b
(A)의 복사본을 만드는b
에서보다는 포인트b
같은 이유로var c uint64 = b
복사본을 만듭니다를 다음과 같은 경우b
나중에 변경,s
그리고c
원래 값이 아닌 새로운 하나가 가정된다.
인터페이스에 저장된 값은 임의로 클 수 있지만 인터페이스 구조에서 값을 보유하기 위해 한 단어 만 사용되므로 할당은 힙에 메모리 청크를 할당하고 포인터를 한 단어 슬롯에 기록합니다.
답변
interface{}
사용자 정의 유형을 포함하여 모든 유형의 값을 넣을 수 있음을 의미합니다. Go의 모든 유형은 빈 인터페이스를 충족합니다 ( interface{}
빈 인터페이스 임).
귀하의 예에서 메시지 필드는 모든 유형의 값을 가질 수 있습니다.
예:
package main
import (
"fmt"
)
type Body struct {
Msg interface{}
}
func main() {
b := Body{}
b.Msg = "5"
fmt.Printf("%#v %T \n", b.Msg, b.Msg) // Output: "5" string
b.Msg = 5
fmt.Printf("%#v %T", b.Msg, b.Msg) //Output: 5 int
}
답변
빈 인터페이스 라고하며 모든 유형으로 구현되므로 Msg
필드 에 무엇이든 넣을 수 있습니다 .
예 :
body := Body{3}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:3}
body = Body{"anything"}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:"anything"}
body = Body{body}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:main.Body{Msg:"anything"}}
이것은 유형이 인터페이스의 모든 메소드를 갖 자마자 인터페이스를 구현한다는 사실의 논리적 확장입니다.
답변
이미 좋은 답변이 있습니다. 직관적으로 이해하려는 다른 사람들을 위해 내 자신을 추가하겠습니다.
상호 작용
하나의 메소드가있는 인터페이스는 다음과 같습니다.
type Runner interface {
Run()
}
따라서 Run()
메소드 가있는 모든 유형 은 Runner 인터페이스를 충족시킵니다.
type Program struct {
/* fields */
}
func (p Program) Run() {
/* running */
}
func (p Program) Stop() {
/* stopping */
}
-
프로그램 유형에도 Stop 메소드가 있지만 필요한 모든 인터페이스 메소드를 갖기 만하면되기 때문에 Runner 인터페이스를 여전히 만족시킵니다.
-
따라서 Run 메소드가 있으며 Runner 인터페이스를 충족시킵니다.
빈 인터페이스
메소드가없는 명명 된 빈 인터페이스는 다음과 같습니다.
type Empty interface {
/* it has no methods */
}
따라서 모든 유형이이 인터페이스를 충족합니다. 이 인터페이스를 만족시키기위한 방법이 필요하지 않기 때문입니다. 예를 들면 다음과 같습니다.
// Because, Empty interface has no methods, following types satisfy the Empty interface
var a Empty
a = 5
a = 6.5
a = "hello"
그러나 위의 프로그램 유형이이를 만족합니까? 예:
a = Program{} // ok
interface {}는 위의 빈 인터페이스와 같습니다.
var b interface{}
// true: a == b
b = a
b = 9
b = "bye"
보시다시피, 신비한 것은 없지만 남용하기는 매우 쉽습니다. 최대한 멀리 떨어져 있으십시오.
답변
로부터 Golang 사양 :
인터페이스 유형은 해당 인터페이스라고하는 메소드 세트를 지정합니다. 인터페이스 유형의 변수는 인터페이스의 상위 집합 인 메소드 세트를 사용하여 모든 유형의 값을 저장할 수 있습니다. 이러한 유형은 인터페이스를 구현한다고합니다. 초기화되지 않은 인터페이스 유형의 변수 값은 nil입니다.
유형은 메소드의 서브 세트를 포함하는 인터페이스를 구현하므로 여러 가지 고유 한 인터페이스를 구현할 수 있습니다. 예를 들어, 모든 유형은 빈 인터페이스를 구현합니다.
상호 작용{}
파악해야 할 개념은 다음과 같습니다.
- 모든 유형이 있습니다. 당신의 지금 T.하자 말을 부르 자, 새로운 유형을 정의 할 수 있습니다 우리의 유형은
T
3 가지 방법이 있습니다A
,B
,C
. - 유형에 지정된 메소드 세트를 ” 인터페이스 유형 ” 이라고합니다 . 우리의 예에서 T_interface라고 부르겠습니다. 동일하다
T_interface = (A, B, C)
- 메소드 의 서명 을 정의하여 “인터페이스 유형”을 작성할 수 있습니다 .
MyInterface = (A, )
- “interface type” 유형 의 변수 를 지정 하면 인터페이스의 상위 집합 인 인터페이스가있는 유형 만 변수 에 지정할 수 있습니다. 즉, 포함 된 모든 메소드 가 내부에 포함되어야합니다.
MyInterface
T_interface
모든 유형의 모든 “인터페이스 유형”이 빈 인터페이스의 수퍼 세트라고 추론 할 수 있습니다.
답변
@VonC의 탁월한 답변과 @ NickCraig-Wood의 주석을 확장하는 예제입니다. interface{}
무엇이든 가리킬 수 있으며 사용하려면 캐스트 / 유형 어설 션이 필요합니다.
package main
import (
. "fmt"
"strconv"
)
var c = cat("Fish")
var d = dog("Bone")
func main() {
var i interface{} = c
switch i.(type) {
case cat:
c.Eat() // Fish
}
i = d
switch i.(type) {
case dog:
d.Eat() // Bone
}
i = "4.3"
Printf("%T %v\n", i, i) // string 4.3
s, _ := i.(string) // type assertion
f, _ := strconv.ParseFloat(s, 64)
n := int(f) // type conversion
Printf("%T %v\n", n, n) // int 4
}
type cat string
type dog string
func (c cat) Eat() { Println(c) }
func (d dog) Eat() { Println(d) }
i
값이있는 빈 인터페이스의 변수입니다 cat("Fish")
. 인터페이스 유형의 값에서 메소드 값을 작성하는 것이 합법적입니다. https://golang.org/ref/spec#Interface_types를 참조 하십시오 .
타입 스위치 i
는 인터페이스 타입이 임을 확인 cat("Fish")
합니다. https://golang.org/doc/effective_go.html#type_switch를 참조 하십시오 . i
그런 다음에 다시 할당됩니다 dog("Bone")
. 유형 스위치는 i
인터페이스 유형이로 변경 되었음을 확인합니다 dog("Bone")
.
또한 할당을 시도 하여 유형 T
이 인터페이스 I
를 구현 하는지 확인하도록 컴파일러에 요청할 수 있습니다 var _ I = T{}
. 참조 https://golang.org/doc/faq#guarantee_satisfies_interface 및 https://stackoverflow.com/a/60663003/12817546 .
모든 유형은 빈 인터페이스를 구현합니다 interface{}
. 참조 https://talks.golang.org/2012/goforc.slide#44 및 https://golang.org/ref/spec#Interface_types . 이 예에서는 이번에 i
는 문자열 “4.3”에 다시 할당됩니다. i
다음 새로운 문자열 변수에 할당 s
하여 i.(string)
전에 s
float64 형식으로 변환되어 f
사용 strconv
. 마지막으로 4와 같은 int 형식 으로 f
변환됩니다 n
. 형식 변환과 형식 어설 션의 차이점 은 무엇입니까?를 참조하십시오 .
Go의 내장 된 맵과 슬라이스와 빈 인터페이스를 사용하여 컨테이너를 생성하는 기능 (명시 적 언 박싱 포함)은 일반적으로 덜 매끄럽다면 제네릭이 가능하게하는 코드를 작성할 수 있다는 것을 의미합니다. https://golang.org/doc/faq#generics를 참조 하십시오 .