데이터 (유형 인터페이스 {})를 유형 문자열로 변환 할 수 없음 : 유형 어설 션 필요


178

나는 아주 새로운 것이었고 나는이 알림 패키지를 가지고 놀고있었습니다 .

처음에는 다음과 같은 코드가있었습니다.

func doit(w http.ResponseWriter, r *http.Request) {
    notify.Post("my_event", "Hello World!")
    fmt.Fprint(w, "+OK")
}

Hello World!의 함수에는 개행 문자를 추가하고 싶었습니다 doit. 왜냐하면 꽤 간단 하기는하지만 handler나중에 다음과 같이하기 때문입니다.

func handler(w http.ResponseWriter, r *http.Request) {
    myEventChan := make(chan interface{})
    notify.Start("my_event", myEventChan)
    data := <-myEventChan
    fmt.Fprint(w, data + "\n")
}

go run:

$ go run lp.go 
# command-line-arguments
./lp.go:15: invalid operation: data + "\n" (mismatched types interface {} and string)

약간의 인터넷 검색 후 나는 이 질문을 SO 에서 발견 했다 .

그런 다음 코드를 다음과 같이 업데이트했습니다.

func handler(w http.ResponseWriter, r *http.Request) {
    myEventChan := make(chan interface{})
    notify.Start("my_event", myEventChan)
    data := <-myEventChan
    s:= data.(string) + "\n"
    fmt.Fprint(w, s)
}

이것이 내가해야했던 일입니까? 컴파일러 오류가 사라 졌으므로 꽤 좋을 것 같습니다. 이것이 효율적입니까? 다르게해야합니까?

답변:


292

Go 사양 에 따르면 :

인터페이스 유형의 표현식 x 및 유형 T의 경우, 기본 표현식 x. (T)는 x가 nil이 아니며 x에 저장된 값이 T 유형임을 주장합니다.

"유형 어설 션"을 사용하면 인터페이스 값에 특정 콘크리트 유형이 포함되어 있거나 콘크리트 유형이 다른 인터페이스를 충족한다고 선언 할 수 있습니다.

귀하의 예에서 데이터를 주장하고있었습니다 (type interface {})에 구체적 유형 문자열이 있습니다. 당신이 잘못되면, 프로그램은 런타임에 패닉합니다. 효율성에 대해 걱정할 필요가 없습니다. 검사는 두 개의 포인터 값을 비교하면됩니다.

문자열인지 확실하지 않은 경우 두 반환 구문을 사용하여 테스트 할 수 있습니다.

str, ok := data.(string)

데이터가 문자열이 아닌 경우 ok는 false입니다. 그런 다음과 같은 명령문을 if 문으로 랩핑하는 것이 일반적입니다.

if str, ok := data.(string); ok {
    /* act on str */
} else {
    /* not string */
}

29

유형 어설 션

이것은 type assertiongolang 으로 알려져 있으며 일반적인 관행입니다.

다음은 둘러보기의 설명 입니다 .

형식 어설 션은 인터페이스 값의 기본 구체적인 값에 대한 액세스를 제공합니다.

t := i.(T)

이 명령문은 인터페이스 값 i가 구체적 유형 T를 보유하고 기본 T 값을 변수 t에 지정 한다고 주장합니다 .

내가 T를 보유하지 않으면, 진술은 공황을 유발할 것입니다.

인터페이스 값에 특정 유형이 있는지 여부를 테스트하기 위해 유형 어설 션은 기본 값과 어설 션 성공 여부를보고하는 부울 값의 두 값을 반환 할 수 있습니다.

t, ok := i.(T)

i에 T가 있으면 t가 기본 값이되고 ok가 true가됩니다.

그렇지 않은 경우 ok는 false이고 t는 T 유형의 0 값이며 패닉은 발생하지 않습니다.

참고 : i은 인터페이스 유형이어야합니다 .

함정

i인터페이스 유형 인 경우에도 인터페이스 유형 []i이 아닙니다. 결과적으로 []i값 유형 으로 변환 하려면 개별적으로 수행해야합니다.

// var items []i
for _, item := range items {
    value, ok := item.(T)
    dosomethingWith(value)
}

공연

성능에 관해서는 이 stackoverflow answer 에 표시된 것처럼 실제 값에 직접 액세스하는 것보다 느릴 수 있습니다 .


13
//an easy way:
str := fmt.Sprint(data)

21
이 답변이 현재 문제를 해결하는 데 OP에 어떻게 도움이되는지에 대한 답변이 포함 된 설명을 추가하십시오
ρяσѕρєя K

3

@ ρяσѕρєя의 요청에 따라 https://golang.org/pkg/fmt/#Sprint 에서 설명을 찾을 수 있습니다 . 관련 설명은 https://stackoverflow.com/a/44027953/12817546https://stackoverflow.com/a/42302709/12817546 에서 찾을 수 있습니다 . @Yuanbo의 답변은 다음과 같습니다.

package main

import "fmt"

func main() {
    var data interface{} = 2
    str := fmt.Sprint(data)
    fmt.Println(str)
}

1
@ Yuanbo 's를 간단히 편집하여 두 답변을 결합 할 수 있다고 생각합니다. 둘 다 적립되며 각각의 '유용성'점수를 합산합니다.
Gwyneth Llewelyn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.