无法将数据(类型接口{})转换为类型字符串:需要类型断言

Alf*_*red 160 go type-mismatch

我很新,我正在玩这个通知包.

起初我的代码看起来像这样:

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

我想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")
}
Run Code Online (Sandbox Code Playgroud)

之后go run:

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

经过一段谷歌搜索后,我发现了这个问题.

然后我将我的代码更新为:

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)
}
Run Code Online (Sandbox Code Playgroud)

这是我应该做的吗?我的编译器错误消失了,所以我觉得这很好吗?这有效吗?你应该采用不同的方式吗?

Ste*_*erg 279

根据Go规范:

对于接口类型和类型T的表达式x,主表达式x.(T)断言x不是nil,并且存储在x中的值是T类型.

"类型断言"允许您声明接口值包含某个具体类型或其具体类型满足另一个接口.

在您的示例中,您断言数据(类型interface {})具有具体类型字符串.如果你错了,程序会在运行时发生恐慌.您无需担心效率,只需要比较两个指针值.

如果您不确定它是否是字符串,您可以使用两种返回语法进行测试.

str, ok := data.(string)
Run Code Online (Sandbox Code Playgroud)

如果数据不是字符串,则ok将为false.然后将这样的语句包装成if语句是很常见的:

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


ciz*_*ixs 23

键入断言

type assertion在golang中是众所周知的,这是一种常见的做法.

以下是go之旅的解释:

类型断言提供对接口值的基础具体值的访问.

t := i.(T)
Run Code Online (Sandbox Code Playgroud)

该语句断言接口值 i保持具体类型 T并将基础T值分配给变量t.

如果我没有持有T,该声明将引发恐慌.

要测试接口值是否包含特定类型,类型断言可以返回两个值:基础值和报告断言是否成功的布尔值.

t, ok := i.(T)
Run Code Online (Sandbox Code Playgroud)

如果我持有T,则t将成为基础值,ok将成立.

如果没有,ok将为false并且t将是T类型的零值,并且不会发生恐慌.

注意:i应为接口类型.

陷阱

即使i是接口类型,[]i也不是接口类型.因此,为了转换[]i为其值类型,我们必须单独执行:

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

性能

至于性能,它可能比直接访问实际值慢,如此stackoverflow答案中所示.


小智 12

//an easy way:
str := fmt.Sprint(data)
Run Code Online (Sandbox Code Playgroud)

  • 添加一些解释,回答这个答案如何帮助OP解决当前问题 (17认同)

Tom*_*m L 6

正如@??????? 可以在https://golang.org/pkg/fmt/#Sprint找到解释。相关解释可以在/sf/answers/3081956741//sf/answers/2961189661/ 找到。这是@Yuanbo 的完整回答。

package main

import "fmt"

func main() {
    var data interface{} = 2
    str := fmt.Sprint(data)
    fmt.Println(str)
}
Run Code Online (Sandbox Code Playgroud)

  • 我想你可以通过简单地编辑 @Yuanbo 的答案来合并这两个答案 - 你们都会被记入并添加各自的“有用性”分数 (2认同)