- 基本的な型: go の最も基本的な型には、整数 (
- int、uint、int8、uint8、int16、uint16、int32、uint32、int64、uint64、byte、rune
など)、浮動小数点型 (
float32、float64)、文字列(
stringは []rune 配列でもあります)、あまり一般的ではありませんが複数型 (
complex64/complex128) です。
複合タイプ: 主に - structural
と
arrayが含まれます。
参照タイプ: - スライス、マップ、チャネル、ポインター
。
インターフェイス タイプ: - エラー、io.Reader など。
。
== を使用する必要があります。たとえ底部のタイプが同じであっても、両側のタイプは一貫している必要があります。以下のコードを見てください
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) }したがって、go は暗黙的な変換を行いません。基になる型が一貫していても、それらを比較することはできません。
次に、異なるタイプから比較できるかどうかを分析します。
package main import "fmt" func main() { var a int = 0 var b int = 1 // 输出false fmt.Println(a == b) }But inまた、浮動小数点型の比較は現実と同じではないことに注意してください。たとえば、計算で 0.1 0.2 の結果は 0.3 ではなく、0.30000000000000004 になります。 draveness を見てください( https://github.com/draveness) ボスによるこの記事 https://draveness.me/whys-the...Compound typeArrayGo アレイとスライスの違いは、インタビューでよく質問されます。 Go の配列の長さは最初に決定する必要があります。つまり、長さを拡張することはできません。値のコピーなので、パラメータを関数に渡して変更しても、外部の値は変わりません。スライスはその逆です。したがって、配列が比較できるかどうかは、次の例を見てください。
package main
import "fmt"
func main() {
var a float64=0.1
var b float64=0.2
// 0.30000000000000004
fmt.Println(a+b)
}
同じ長さの配列は比較できますが、異なる長さの配列は比較できないことがわかります。理由は何ですか?これは、配列型では配列の長さも型の一部であるためで、長さが異なる配列は異なる型とみなされ、比較することができません。
構造同じ
は同じです。
Struct の比較も内部型から始まり、各型の値は等しい場合のみ等しくなります。以下の例: <pre class="brush:php;toolbar:false">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)
}</pre>
したがって、Struct
構造体を比較できることがわかります。別の例を見てみましょう。
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 }
はどのようにして再び比類のないものになったのでしょうか?これは、以下の参照タイプによって異なります。 参照型
上記の例の構造はスライスと比較できません。goでは、
Sliceと
Mapが比較できない型として定義されています。 。 を見てみましょう。
Slice
が同等である場合、同じスライスを定義するために何が使用されますか?アドレスを使用する場合、2 つのアドレスが指す
が同じである場合はどうなるでしょうか?これは明らかに不適切です。配列と同じである場合、スライスを展開すると等しくなくなります。したがって、長さと容量を比較することは困難です。この問題は言語レベルで解決できますが、golang チームは、努力する価値はないと考えています。したがって、Slice
は比較不可能とみなされます。 同じ
Map も比較不可能な型として定義されています。参照型は比較できないのでしょうか? いいえ、例を見てください:
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) }
参照型変数には、特定の変数のメモリ アドレスが格納されます。したがって、参照型変数を比較すると、2 つの参照型が同じ変数を格納するかどうかが決まります。
同じ変数の場合、メモリ アドレスは同じである必要があり、参照型変数は等しいため、「==」を使用して true を判断します。Ifは同じ変数ではなく、メモリです。 アドレスは明らかに異なり、「==」の結果は false です。- インターフェイスの種類
- Go 言語では、インターフェイスの種類を次の 2 つのカテゴリに分類します。インターフェイス タイプに一連のメソッドが含まれているかどうか:
- 使用
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
- 复合类型中如果带有不可比较的类型,那么该类型也是不可比较的。可以理解不可比较类型具有传递性。