Maison >développement back-end >Golang >Analyser la comparaison des types en cours

Analyser la comparaison des types en cours

藏色散人
藏色散人avant
2021-06-21 16:09:533383parcourir

La colonne tutorielle suivante de golang vous présentera l'analyse de la comparaison de types en go. J'espère qu'elle sera utile aux amis dans le besoin !

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

ac类型相同(都是int),值也相同(都是0,基本类型比较),故两者相等。 ab类型相同,值不等,故两者不等。 ad类型不同,aintdfloat64,故两者不等。

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

ab类型相同(都是A),值也相同(结构体A),故两者相等。 ac类型相同,值不同,故两者不等。 de类型相同(都是*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)

ab的类型是切片类型,而切片类型不可比较,所以a == bpanic

接口值的比较不要求接口类型(注意不是动态类型)完全相同,只要一个接口可以转化为另一个就可以比较。例如:

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
  • 复合类型中如果带有不可比较的类型,那么该类型也是不可比较的。可以理解不可比较类型具有传递性。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer