Go语言中的<断言>

cc7756789w · · 5026 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

废话

为什么要给标题加上符号着重一下?难道编程语言中的思想不都是一样的吗?

的确,基本思想大同小异,各自实现的原理和设计哲学会有差异。

如果你之前没有使用过Go语言,那么你很自然的认为,Go语言中一定有assert之类的操作符或函数。答案是没有,这可能会让你很失望,你兴冲冲地看着某篇介绍Go语言的文章,当看到Go中的关键字如此之少的时候,你或许会赞叹:如此简洁!但当你正式编写代码却发现:这语言用着很不爽!没有try catch,没有泛型,没有断言,必须把起始括号放在语句末尾……

其实你陷入了一个误区,你以其他语言的视角来看待Go语言,自然得不到满意的结果。

问题

早晨我逛stackoverflow的时候看到了这个问题:
http://stackoverflow.com/questions/8103617/call-a-struct-and-its-method-by-name-in-go

我很自然的想用其他语言,如Python的字典,JS的对象字面量来对一个对象进行映射。

因此我这个学了几天Go的小财笔写了如下测试:

package main

import (
    "fmt"
    "reflect"
)

type MyStruct struct {
}

func (a *MyStruct) Action() {
    fmt.Println("Hello")
}

func main() {
    var M map[string]interface{}
    M = make(map[string]interface{}, 100)
    M["MyStruct"] = &MyStruct{}
    m := M["MyStruct"]
    fmt.Println(reflect.TypeOf(m)) // *main.MyStruct
    m.Action()
}

结果是编译报错:
m.Action undefined (type interface {} is interface with no methods)

在线运行实例(一般人都认为没有golang.org这个网站,请自行解决访问方式)
https://play.golang.org/p/qnpHmY9S73

我很奇怪,reflect.TypeOf明明检测出类型是MyStruct,为什么没有方法呢?

我忽略了一个很明显的问题,同时也没有去看官方文档。
https://golang.org/ref/spec#Type_assertions

Stackoverflow上的朋友给了我完美的答案:http://stackoverflow.com/questions/36439733/how-to-referencing-an-object-with-map/36439925#36439925

我声明map的时候,声明的值是interface{}类型,因此,interface类型并没有方法。

这是官方文档上的例子:

var x interface{} = 7  // x has dynamic type int and value 7
i := x.(int)           // i has type int and value 7

而解决的方法很简单,用Go语言提供的类型检测方法,同时也可作为断言的解决方案:

package main

import (
    "fmt"
    "reflect"
)

type MyStruct struct {
}

func (a *MyStruct) Action() {
    fmt.Println("Hello")
}

func main() {
    var M map[string]interface{}
    M = make(map[string]interface{}, 100)
    M["MyStruct"] = &MyStruct{}
    om := M["MyStruct"]            // the type of variable m is interface
    m := om.(*MyStruct)            // so asserts that value restored in m
    fmt.Println(reflect.TypeOf(m)) // *main.MyStruct
    m.Action()
}

https://play.golang.org/p/mjxkAeRuDV

m := om.(*MyStruct)

  • 如果om是MyStruct类型,则将转换后的类型赋值给m。
  • 如果MyStruct被定义为一个接口,只要实现了这个接口的对象,此操作都会成功。

不过需要注意的是,如果false了,也就是不匹配,就会产生panic错误。

还有一种不产生错误的方法。

m, ok := om.(*MyStruct)

使用两个变量接受返回值,如果ok为false,则m为零值,但是不会报错。

因此你可以这样来进行错误处理:

if !ok {
    fmt.Println("Type not matched!")
    os.Exit(1)
}

这其实就是Go中简洁但被诟病的value, err := F()设计哲学。有人调侃:当用其他语言在编写功能的时候,用Go已经把功能写好了,但当用其他语言写的产品已经在测试了,用Go语言的人还在写if err { ... }

结论

英文不提高,不首先去看官网文档,你都是个屁。


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:cc7756789w

查看原文:Go语言中的<断言>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

5026 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传