Overview
In a recent interview, the interviewer asked about the types between go In comparison, the answer is not very good. Fundamentally speaking, the foundation is not solid enough! I read a bunch of information on the Internet and made some simple summaries myself, haha!
Types in go
First let’s take a look at the most basic centralized types included in go
- Basic types: The most basic types in go include integers (
int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, byte, rune
, etc.), floating point type (float32, float64
), string (string
is also a []rune array) and a less commonly used plural type (complex64/complex128
). - Composite type: mainly includes
structure
andarray
. - Reference types:
Slice, Map, Channel, pointer
. - Interface type:
Error, io.Reader, etc.
.
As a strongly typed language, go will not automatically help us perform type conversion with high-level languages such as PHP, so we must use ==
when comparing. The types on both sides must be consistent. Even if their bottom types are the same. Look at the code below
package main import "fmt" type A struct { Id int } type B struct { Id int } func main() { var a int var b int16 // 编译报错:invalid operation a == b (mismatched types int and int16) fmt.Println(a == b) aStruct := A{Id:5} bStruct := B{Id:5} // 编译报错:invalid operation: aStruct == bStruct (mismatched types A and B) fmt.Println(aStruct == bStruct) }
So go will not do implicit conversion for us. Even if the underlying types are consistent, they cannot be compared.
Next we analyze whether comparisons can be made from different types.
Basic type
The basic type of go is relatively simple. As long as the type is the same, then they can be compared. For example:
package main import "fmt" func main() { var a int = 0 var b int = 1 // 输出false fmt.Println(a == b) }
But in the basic type Also note that the comparison of floating point types is not the same as in reality. For example, the result of 0.1 0.2 in calculation is not 0.3, but 0.30000000000000004.
package main import "fmt" func main() { var a float64=0.1 var b float64=0.2 // 0.30000000000000004 fmt.Println(a+b) }
Why is this? You can look at draveness( https://github.com/draveness) This article by the boss https://draveness.me/whys-the...
Compound type
Array
The difference between go arrays and slices is often asked in interviews. The length of an array in Go must be determined first, that is, the length cannot be expanded. And it is a value copy. If the parameters are passed to a function and modified, the external value will remain the same. Slice is the opposite. So whether arrays can be compared, look at the following example:
package main import "fmt" func main() { a := [2]int{1, 2} b := [2]int{1, 2} c := [2]int{1, 3} d := [3]int{1, 2, 4} fmt.Println(a == b) // true fmt.Println(a == c) // false fmt.Println(a == d) // invalid operation: a == d (mismatched types [2]int and [3]int) }
It can be seen that arrays of the same length can be compared, but arrays of different lengths cannot be compared
. what is the reason? This is because in the array type, the length of the array is also part of the type. Arrays of different lengths are considered to have different types, so they cannot be compared.
Structure
The same Struct
is the same. The comparison of Struct
also starts from the internal type, and the values of each type are equal only when they are equal. The following example:
package main import "fmt" type A struct { id int name string } func main() { a := A{id:5,name:"123"} b := A{id:5,name:"123"} c := A{id:5,name:"1234"} fmt.Println(a == b) // true fmt.Println(a == c) // false }
So it can be understood that Struct
structures can be compared. Let’s look at another example: How did
package main import "fmt" type A struct { id int name string son []int } func main() { a := A{id:5,name:"123",son:[]int{1,2,3}} b := A{id:5,name:"123",son:[]int{1,2,3}} fmt.Println(a == b) // invalid operation: a == b (struct containing []int cannot be compared) }
become incomparable again? This depends on the reference type below.
Reference type
The above example structure cannot be compared with slices. In go, Slice
and Map
are defined as Types that cannot be compared. Let's look at
If Slice
is comparable, then what is used to define the same slice? If you use an address, what if the Slice
pointed to by the two addresses is the same? This is obviously inappropriate. If it is the same as the array, then if I expand the slice, it will not be equal. Therefore, length and capacity are difficult to compare. Although this problem can be solved at the language level, the golang team believes that it is not worth the effort. Therefore Slice
is regarded as incomparable.
The same Map
is also defined as an incomparable type. So are reference types incomparable? No, look at an example:
package main import "fmt" type A struct { id int name string } func main() { a := &A { a : 1, b : "test1" } b := &A { a : 1, b : "test1" } c := a fmt.Println(a == b) // false fmt.Println(a == c) // true ch1 := make(chan int, 1) ch2 := make(chan int, 1) ch3 := ch1 fmt.Println(ch1 == ch2) // false fmt.Println(ch1 == ch3) // true }
Reference type variables store the memory address of a certain variable. Therefore, the comparison of reference type variables determines whether the two reference types store the same variable.
- If it is the same variable, the memory address must be the same, then the reference type variables are equal, and "==" is used to determine true
- If they are not the same variable, the memory The addresses are definitely different, and the "==" result is false
Interface type
Go language divides interface types into two categories according to whether the interface type contains a set of methods:
- 使用
runtime.iface
结构体表示包含方法的接口 - 使用
runtime.eface
结构体表示不包含任何方法的interface{}
类型
type eface struct { // 16 字节 _type *_type data unsafe.Pointer } type iface struct { // 16 字节 tab *itab data unsafe.Pointer }
所以我们可以得知,一个接口值是由两个部分组成的,即该接口对应的类型和接口对应具体的值。接口值的比较涉及这两部分的比较,只有当类型和值都相等(动态值使用==
比较),两个接口值才是相等的。看个例子:
var a interface{} = 0 var b interface{} = 2 var c interface{} = 0 var d interface{} = 0.0 fmt.Println(a == b) // false fmt.Println(a == c) // true fmt.Println(a == d) // false
a
和c
类型相同(都是int
),值也相同(都是0
,基本类型比较),故两者相等。 a
和b
类型相同,值不等,故两者不等。 a
和d
类型不同,a
为int
,d
为float64
,故两者不等。
type A struct { a int b string } var a interface{} = A { a: 1, b: "test" } var b interface{} = A { a: 1, b: "test" } var c interface{} = A { a: 2, b: "test" } fmt.Println(a == b) // true fmt.Println(a == c) // false var d interface{} = &A { a: 1, b: "test" } var e interface{} = &A { a: 1, b: "test" } fmt.Println(d == e) // false
a
和b
类型相同(都是A
),值也相同(结构体A
),故两者相等。 a
和c
类型相同,值不同,故两者不等。 d
和e
类型相同(都是*A
),值使用指针(引用)类型的比较,由于不是指向同一个地址,故不等。
不过需要注意的是,如果接口中类型是切片或者Map
不可比较的类型,那么会直接报错的。看个例子:
var a interface{} = []int{1, 2} var b interface{} = []int{1, 2} // panic: runtime error: comparing uncomparable type []int fmt.Println(a == b)
a
和b
的类型是切片类型,而切片类型不可比较,所以a == b
会panic
。
接口值的比较不要求接口类型(注意不是动态类型)完全相同,只要一个接口可以转化为另一个就可以比较。例如:
var f *os.File var r io.Reader = f var rc io.ReadCloser = f fmt.Println(r == rc) // true var w io.Writer = f // invalid operation: r == w (mismatched types io.Reader and io.Writer) fmt.Println(r == w)
r
的类型为io.Reader
接口,rc
的类型为io.ReadCloser
接口。查看源码,io.ReadCloser
的定义如下:
type ReadCloser interface { Reader Closer }
io.ReadCloser
可转化为io.Reader
,故两者可比较。
而io.Writer
不可转化为io.Reader
,编译报错。
总结
- 可比较:
int、ifloat、string、bool、complex、pointe、channel、interface、array
- 不可比较:
slice、map、function
- 复合类型中如果带有不可比较的类型,那么该类型也是不可比较的。可以理解不可比较类型具有传递性。