设为首页 加入收藏

TOP

从一道面试题来谈谈Golang中的 ==(一)
2023-08-06 07:49:41 】 浏览:166
Tags:从一道 谈谈 Golang

写这篇文章的时候,已经离我找工作有一段时间了,但是觉得这道题不管是面试还是日常的工作中,都会经常遇到,所以还是特意写一篇文章,记录下自己对Golang中==的理解。如文章中出现不对的地方,请不吝赐教,谢谢。

注意,以下文章内容是基于 go1.16.4 进行演示的,如果和你验证时,结果不一致,可能 Go 的判断规则有所改变。

1、面试题

大家可以先不看结果,想想答案,再看后面的结果以及相关的分析。

type T interface {

}

func main()  {

	var (
		t T
		p *T

		i1 interface{} = t
		i2 interface{} = p
	)

	fmt.Println(i1 ==t, i1 == nil)
	fmt.Println(i2 ==p, i2 == nil)
	fmt.Println(t == nil)
	fmt.Println(p == nil)

}

执行结果:

true true
true false
true
true

分析:

1、interface 值由动态类型动态值组成。只有在类型都相同时才相等。接口变量i1是接口类型的零值,也就是它的类型和值部分都是nil,接口变量i2的动态值虽然是零值,但是动态类型为 *T
2、变量 t、p 都没有初始化,未分配内存,所以 变量t、p 都等于 nil。

对于上面的描述不太清楚的同学,不用着急,我们一起来学习 Golang 中的==,有较为详细的介绍。

2、Golang中的数据类型

Golang中的数据类型分为4大类,他们分别是:

  1. 基本类型 (Primary types): 整型(int/uint/int8/uint8/int16/uint16/int32/uint32/int64/uint64/byte/rune等)、浮点数(float32/float64)、复数类型(complex64/complex128)、字符串(string)、布尔(true/false)。这些是Go语言内置的基本数据类型,它们是Go语言的原始数据类型,不能再细分。
  2. 复合类型 (Composite types):又叫聚合类型。包括数组、结构体。复合类型允许将多个值组合成一个新的数据结构。
  3. 引用类型 (Reference types):这些类型在内存中存储的是数据的地址,包括 指针、切片(slice)、映射(map)、通道(channel)、函数类型(func)。引用类型允许在函数间共享和修改数据。
  4. 接口类型 (Interface types):接口类型是一种抽象类型,它定义了对象的行为,而不关心对象的具体类型。通过实现接口,可以实现多态性和代码复用。比如 error

其实接口类型可以看作是引用类型,在 Go 中,接口类型是一种特殊的引用类型,它包含一个指向实际数据的指针以及类型信息。当你将一个具体类型的值赋给接口变量时,接口会存储一个指向实际数据的指针或实际数据的拷贝。因此,接口可以看作是对其他类型的引用,而不是直接包含实际数据。

在Go语言中,自定义类型属于基本类型的概念中。

自定义类型属于基本类型的一种,它通过使用 type 关键字来创建新的类型,底层使用基本数据类型。通过自定义类型,我们可以为基本类型赋予更多语义,并且可以为它们定义自己的方法。自定义类型和其他基本类型具有相同的操作和运算规则,但在类型系统中它们是不同的类型。

例如使用 type number int64 时,我们自定义了一种数据类型,叫做number。虽然它底层使用了int64,但在类型系统中,numberfloat64是不同的类型。

在Go语言中,还有一种类型别名的叫法,是 Go1.9 引用的新功能。

类型别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型。例如:

type byte = uint8
type rune = int32

==操作最重要的一个前提是:两个操作数类型必须相同!!!

golang 的类型系统非常严格,没有C/C++/python中的隐式类型转换。这个需要注意。

3、四大类型如何使用 ==

3.1、基本类型

基本类型的比较,就比较简单直观,直接使用==判断就好了,注意的是Go中并没有隐式转换,而且类型一致才可以

package main

import "fmt"

func main() {
	var a int64
	var b int64
	var c int32

	fmt.Println(a == b)
	fmt.Println(c)

	// Invalid operation: a == c (mismatched types int64 and int32)
	//fmt.Println(a == c)
}

接下来我们看看浮点数的比较:

package main

import "fmt"

func main() {
	var a float64 = 0.1
	var b float64 = 0.2
	var c float64 = 0.3

	fmt.Println(a + b)  // 0.30000000000000004
	fmt.Println(a+b == c)  // false

}

是不是有点小惊讶,这个是因为Go 中的 浮点数遵循 IEEE 754 标准,所以会有有些浮点数不能精确表示,浮点运算结果会有误差。

想大概了解计算机是如何表示浮点数的可以看看下面的文章,有一个基础的了解。

数字编码

注意:

浮点数做 判等 操作一般是使用 计算两个浮点数的差的绝对值,如果小于一定的值就认为它们相等,比如1e-9

package main

import (
	"fmt"
	"math"
)

func main() {
	var a = 0.1
	var b = 0.2
	var c = 0.3

	fmt.Println(a + b)  // 0.30000000000000004
	fmt.Println(math.Abs((a+b)-c) < 1e-9) // true
	fmt.Printf("%T", a) // float64
}

3.2、复合类型

合类型也叫做聚合类型。golang 中的复合类型只有两种:数组和结构体。它们是逐元素/字段比较的。

注意:数组的长度视为类型的一部分,长度不同的两个数组是不同的类型,不能直接比较

  • 对于数组来说,依次比较各个元素的值。根据元素类型的不同,再依据是基本类型、复合类型、引用类型或接口类型,按照特定类型的规则进行比较。所有元素全都相等,数组才是相等的。
  • 对于结构体来说,依次比较各个字段的值。根据字段类型的不同,再依据是 4 中类型中的哪一种,按照特定类型的规则进行比较。所有字段全都相等,结构体才是相等的。

注意:如包含了不支持直接使用 == 符号的类型,在编译阶段会报错。

例如:

package main

import "fmt"

type Student struct {
	Name string
	Age  int
	Sex  bool
}

type S1 struct {
	Name   string
	Scores []int8  // 注意这里定义的是 slice 类型
}

type ITest interface{}
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Go 介绍 下一篇小白终于解决了在学习Go中不知道M..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目