关于golang:Go-面试官Go-结构体是否可以比较为什么

51次阅读

共计 3299 个字符,预计需要花费 9 分钟才能阅读完成。

微信搜寻【脑子进煎鱼了】关注这一只爆肝煎鱼。本文 GitHub github.com/eddycjy/blog 已收录,有我的系列文章、材料和开源 Go 图书。

大家好,我是煎鱼。

最近金三银四,是面试的节令。在我的 Go 读者交换群里呈现了许多小伙伴在探讨本人面试过程中所遇到的一些 Go 面试题。

明天的男主角,是 Go 工程师的必修技能,也是极容易踩坑的中央,就是“Go 面试题:Go 构造体(struct)是否能够比拟?

如果能够比拟,是为什么?如果不能够比拟,又是为什么?

请在此处默念本人心目中的答案,再往和煎鱼一起研究一波 Go 的技术哲学。

构造体是什么

在 Go 语言中有个根本类型,开发者们称之为构造体(struct)。是 Go 语言中十分罕用的,根本定义:

type struct_variable_type struct {
    member definition
    member definition
    ...
    member definition
}

简略示例:

package main

import "fmt"

type Vertex struct {
    Name1 string
    Name2 string
}

func main() {v := Vertex{"脑子进了", "煎鱼"}
    v.Name2 = "蒸鱼"
    fmt.Println(v.Name2)
}

输入后果:

蒸鱼

这部分属于基础知识,因而不再过多解释。如果看不懂,倡议重学 Go 语言语法根底。

比拟两下

例子一

接下来正式开始研究 Go 构造体比拟的问题,第一个例子如下:

type Value struct {
    Name   string
    Gender string
}

func main() {v1 := Value{Name: "煎鱼", Gender: "男"}
    v2 := Value{Name: "煎鱼", Gender: "男"}
    if v1 == v2 {fmt.Println("脑子进煎鱼了")
        return
    }

    fmt.Println("脑子没进煎鱼")
}

咱们申明了两个变量,别离是 v1 和 v2。其都是 Value 构造体的实例化,是同一个构造体的两个实例。

他们的比拟后果是什么呢,是输入”脑子进煎鱼了“,还是”脑子没进煎鱼“?

输入后果:

脑子进煎鱼了

最终输入后果是”脑子进煎鱼了“,初步的论断是能够构造体间比拟的。大快人心,那这篇文章是不是就要完结了?

当然不是 … 很多人都会踩到这个 Go 语言的坑,真实情况是构造体是可比拟,也不可比拟的,不要误入歧途了,这是一个十分 “ 乏味 ” 的景象。

例子二

接下来持续革新下面的例子,咱们在本来的构造体中减少了指针类型的援用。

第二个例子如下:

type Value struct {
    Name   string
    Gender *string
}

func main() {v1 := Value{Name: "煎鱼", Gender: new(string)}
    v2 := Value{Name: "煎鱼", Gender: new(string)}
    if v1 == v2 {fmt.Println("脑子进煎鱼了")
        return
    }

    fmt.Println("脑子没进煎鱼")
}

这段程序输入后果是什么呢,咱们猜想一下,变量仍然是同一构造体的两个实例,值的赋值形式和内容都是一样的,是否该当输入“脑子进煎鱼了”?

答案是:脑子没进煎鱼。

例子三

咱们持续不信邪,试试另外的根本类型,看看后果是不是还是相等的。

第三个例子如下:

type Value struct {
    Name   string
    GoodAt []string}

func main() {v1 := Value{Name: "煎鱼", GoodAt: []string{"炸", "煎", "蒸"}}
    v2 := Value{Name: "煎鱼", GoodAt: []string{"炸", "煎", "蒸"}}
    if v1 == v2 {fmt.Println("脑子进煎鱼了")
        return
    }

    fmt.Println("脑子没进煎鱼")
}

这段程序输入后果是什么呢?

答案是:

# command-line-arguments
./main.go:15:8: invalid operation: v1 == v2 (struct containing []string cannot be compared)

程序运行就间接报错,IDE 也提醒谬误,一只煎鱼都没能输入进去。

例子四

那不同构造体,雷同的值内容呢,是否进行比拟?

第四个例子:

type Value1 struct {Name string}

type Value2 struct {Name string}

func main() {v1 := Value1{Name: "煎鱼"}
    v2 := Value2{Name: "煎鱼"}
    if v1 == v2 {fmt.Println("脑子进煎鱼了")
        return
    }

    fmt.Println("脑子没进煎鱼")
}

显然,会间接报错:

# command-line-arguments
./main.go:18:8: invalid operation: v1 == v2 (mismatched types Value1 and Value2)

那是不是就齐全没法比拟了呢?并不,咱们能够借助强制转换来实现:

    if v1 == Value1(v2) {fmt.Println("脑子进煎鱼了")
        return
    }

这样程序就会失常运行,且输入“脑子进煎鱼了”。当然,若是不可比拟类型,仍然是不行的。

为什么

为什么 Go 构造体有的比拟就是失常,有的就不行,甚至还间接报错了。难道是有什么“潜规则”吗?

在 Go 语言中,Go 构造体有时候并不能间接比拟,当其根本类型蕴含:slice、map、function 时,是不能比拟的。若强行比拟,就会导致呈现例子中的间接报错的状况。

而指针援用,其尽管都是 new(string),从表象来看是一个货色,但其具体返回的地址是不一样的。

因而若要比拟,则需改为:

func main() {gender := new(string)
    v1 := Value{Name: "煎鱼", Gender: gender}
    v2 := Value{Name: "煎鱼", Gender: gender}
    ...
}

这样就能够保障两者的比拟。如果咱们被迫无奈,被要求肯定要用构造体比拟怎么办?

这时候能够应用反射办法 reflect.DeepEqual,如下:

func main() {v1 := Value{Name: "煎鱼", GoodAt: []string{"炸", "煎", "蒸"}}
    v2 := Value{Name: "煎鱼", GoodAt: []string{"炸", "煎", "蒸"}}
    if reflect.DeepEqual(v1, v2) {fmt.Println("脑子进煎鱼了")
        return
    }

    fmt.Println("脑子没进煎鱼")
}

这样子就可能正确的比拟,输入后果为“脑子进煎鱼了”。

例子中所用到的反射比拟办法 reflect.DeepEqual 罕用于断定两个值是否深度统一,其规定如下:

  • 雷同类型的值是深度相等的,不同类型的值永远不会深度相等。
  • 当数组值(array)的对应元素深度相等时,数组值是深度相等的。
  • 当构造体(struct)值如果其对应的字段(包含导出和未导出的字段)都是深度相等的,则该值是深度相等的。
  • 当函数(func)值如果都是零,则是深度相等;否则就不是深度相等。
  • 当接口(interface)值如果持有深度相等的具体值,则深度相等。

更具体的大家可到 golang.org/pkg/reflect/#DeepEqual 进行具体查看:

该办法对 Go 语言中的各种类型都进行了兼容解决和判断,因为这不是本文的重点,因而就不进一步开展了。

总结

在本文中,咱们针对 Go 语言的构造体(struct)是否可能比拟进行了具体例子的开展和阐明。

其本质上还是对 Go 语言根本数据类型的了解问题,算是变形到构造体中的具体进一步拓展。

不晓得你有没有在 Go 构造体吃过什么亏呢,欢送在下方评论区留言和咱们一起交换和探讨。

若有任何疑难欢送评论区反馈和交换,最好的关系是相互成就 ,各位的 点赞 就是煎鱼创作的最大能源,感激反对。

文章继续更新,能够微信搜【脑子进煎鱼了】浏览,回复【000】有我筹备的一线大厂面试算法题解和材料;本文 GitHub github.com/eddycjy/blog 已收录,欢送 Star 催更。

正文完
 0