Aperçu
Dans une récente interview, l'intervieweur a posé des questions sur les types entre go In En comparaison, la réponse n'est pas très bonne. Au fond, les fondations ne sont pas assez solides ! Après avoir lu de nombreuses informations sur Internet, j'ai moi-même fait quelques résumés simples, haha !
Types dans go
Tout d'abord, examinons les types centralisés les plus basiques inclus dans go
- Types de base : les types les plus basiques dans go incluent des entiers (
int、uint、int8、uint8、int16、uint16、int32、uint32、int64、uint64、byte、rune
, etc.), le type à virgule flottante (float32、float64
), la chaîne (string
est également un tableau de runes []) et le type de nombre complexe le moins couramment utilisé (complex64/complex128
). - type composé : comprend principalement
结构体
et数组
. - Type de référence :
Slice、Map、Channel、指针
. - Type d'interface :
Error、io.Reader等
.
Go, en tant que langage fortement typé, ne nous aidera pas automatiquement à effectuer une conversion de type avec des langages de haut niveau tels que PHP, nous devons donc utiliser ==
lors de la comparaison des types sur les deux. les côtés doivent être cohérents, même si leurs types de fond sont les mêmes. Non non plus. Regardez le code ci-dessous
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) }
Alors go ne fera pas de conversion implicite pour nous Même si les types sous-jacents sont cohérents, ils ne peuvent pas être comparés.
Ensuite, nous analysons si des comparaisons peuvent être faites à partir de différents types.
Types de base
Les types de base de go sont relativement simples. Tant que les types sont les mêmes, alors ils peuvent être comparés :
package main import "fmt" func main() { var a int = 0 var b int = 1 // 输出false fmt.Println(a == b) }
Mais parmi. les types de base Notez également que la comparaison des types à virgule flottante n'est pas la même qu'en réalité. Par exemple, le résultat de 0,1+0,2 dans le calcul n'est pas 0,3, mais 0,30000000000000004
package main import "fmt" func main() { var a float64=0.1 var b float64=0.2 // 0.30000000000000004 fmt.Println(a+b) }
Pourquoi est-ce possible ? regardez Draveness (https://github.com/draveness) Cet article du patron https://draveness.me/whys-the...
Type composite
Array
La différence entre les go arrays et les slices est souvent posée lors des entretiens. La longueur d'un tableau dans Go doit d'abord être déterminée, c'est-à-dire que la longueur ne peut pas être étendue. Et c'est une copie de valeur Si les paramètres sont passés à une fonction et modifiés, la valeur externe restera la même. Slice est le contraire. Alors pour savoir si les tableaux peuvent être comparés, regardez l'exemple suivant :
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) }
Comme vous pouvez le voir, 相同长度的数组是可以比较的,而不同长度的数组是不能进行比较的
. Quelle en est la raison ? En effet, dans le type tableau, la longueur du tableau fait également partie du type. Les tableaux de différentes longueurs sont considérés comme ayant des types différents, ils ne peuvent donc pas être comparés.
Structure
La même Struct
est la même. La comparaison de Struct
part également du type interne, et les valeurs de chaque type ne sont égales que lorsqu'elles sont égales. L'exemple suivant :
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 }
On comprend alors que les Struct
structures sont comparables. Regardons un autre exemple : comment
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) }
est-il redevenu incomparable ? Cela dépend du type de référence ci-dessous.
Type de référence
Dans l'exemple de structure ci-dessus, la tranche ne peut pas être comparée. En go, Slice
et Map
sont définis comme des types qui ne peuvent pas être comparés. Regardons
Si Slice
est comparable, alors qu'est-ce qui est utilisé pour définir les mêmes tranches ? Si vous utilisez des adresses, que se passe-t-il si les Slice
pointés par les deux adresses sont identiques ? C'est évidemment inapproprié. Si c'est le même que le tableau, alors si j'étends la tranche, elle ne sera pas égale. La longueur et la capacité sont donc difficiles à comparer. Bien que ce problème puisse être résolu au niveau linguistique, l’équipe de Golang estime que cela n’en vaut pas la peine. Donc Slice
est considéré comme incomparable.
De même Map
est également défini comme un type incomparable. Alors tous les types de référence sont-ils incomparables ? Non, regardez un exemple :
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 }
Les variables de type référence stockent l'adresse mémoire d'une certaine variable. Par conséquent, la comparaison des variables de type référence détermine si les deux types de référence stockent la même variable.
- S'il s'agit de la même variable, l'adresse mémoire doit être la même, alors les variables de type référence sont égales, et "==" est utilisé pour déterminer vrai
- Si c'est le cas n'est pas la même variable, alors la mémoire Les adresses sont définitivement différentes, et le résultat "==" est faux
Type d'interface
Le langage Go divise les types d'interface en deux catégories selon si le type d'interface contient un ensemble de méthodes :
- 使用
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
- 复合类型中如果带有不可比较的类型,那么该类型也是不可比较的。可以理解不可比较类型具有传递性。