Можно ли сравнить структуру Голанга?

Go

"Выпуск 8" До 80-го номера дядюшки еще 72 номера., чем дядя хочет поделиться с вами сегодня, так это базовыми знаниями голанга——Можно ли сравнивать структуру?, Этот основной вопрос является проверкой основ и деталей каждого, и это также вопрос, который предпочитают задавать интервьюеры. Давайте посмотрим на него вместе с вами.

Можно ли сравнивать структуру?Очевидно, что это предложение содержит две ситуации:

  • Можно ли сравнивать два экземпляра одной и той же структуры?
  • Можно ли сравнивать два экземпляра разных структур?

фокус

Прежде чем разбирать два вопроса выше, давайте разберемся, какие типы данных сопоставимы, а какие несопоставимы в golang:

  • Сопоставимые:Integer,Floating-point,String,Boolean,Комплекс (множественное число),Pointer,Channel,Interface,Array
  • Не сравнимо:Slice,Map,Function

Проанализируем две описанные выше ситуации по отдельности.

Можно ли сравнивать два экземпляра одной и той же структуры?

Во-первых, давайте создадим структурную структуру для игры с

type S struct {
    Name    string
    Age     int
    Address *int
}

func main() {
    a := S{
        Name:    "aa",
        Age:     1,
        Address: new(int),
    }
    b := S{
        Name:    "aa",
        Age:     1,
        Address: new(int),
    }

   fmt.Println(a == b)
}

Запуск приведенного выше кода обнаруживает, что он напечатает false. Поскольку вывод можно распечатать нормально, значит, его можно сравнить."Два вопроса о смерти"

Что можно сравнить?

Возвращаясь к выделенной выше части, в резюме мы можем знать, что в golangSlice,Map,FunctionЭти три типа данных нельзя сравнивать напрямую. Давайте снова посмотрим на структуру S. Структура не содержит несравнимых переменных-членов, поэтому структуру можно сравнивать напрямую.

Почему он печатает ложь?

Хотя a и b являются двумя экземплярами одной и той же структуры, поскольку значение переменной-указателя Address отличается, a != b, если ab удаляет Address во время инициализации (не инициализирует Address), то a = = b истинно, потому что значение по умолчанию переменной ptr равно нулю, или значение той же переменной-указателя присваивается переменной-члену Address, что также верно.

Что, если в структуру S добавить переменную-член типа Slice?

type S struct {
    Name    string
    Age     int
    Address *int
   Data    []int
}

func main() {
    a := S{
        Name:    "aa",
        Age:     1,
        Address: new(int),
      Data:    []int{1, 2, 3},
    }
    b := S{
        Name:    "aa",
        Age:     1,
        Address: new(int),
      Data:    []int{1, 2, 3},
    }

   fmt.Println(a == b)
}

Что будет напечатано в это время? истинный? ложный? На самом деле запуск приведенного выше кода сообщит о следующей ошибке:

# command-line-arguments
./test.go:37:16: invalid operation: a == b (struct containing []int cannot be compared)

Хотя a, b являются двумя экземплярами одной и той же структуры с одинаковым назначением, поскольку переменные-члены структуры имеют несравнимые элементы (срез), их нельзя сравнивать напрямую с ==, поэтому просто напишите == и сообщите об ошибке

"Суммировать"

Два экземпляра одной и той же структуры можно сравнивать или нет. Если структура не содержит несопоставимых переменных-членов, их можно сравнивать напрямую. В противном случае их нельзя сравнивать напрямую.


Но в обычном практическом процессе, когда нам нужно сравнить экземпляры структур, содержащих типы данных, которые нельзя сравнивать напрямую, нельзя ли сравнивать? На самом деле это не так, golang по-прежнему дружелюбен, мы можем использоватьфункция Reflect.DeepEqualдля сравнения двух переменных. Таким образом, мы можем написать приведенный выше код следующим образом:

type S struct {
    Name    string
    Age     int
    Address *int
   Data    []int
}

func main() {
    a := S{
        Name:    "aa",
        Age:     1,
        Address: new(int),
      Data:    []int{1, 2, 3},
    }
    b := S{
        Name:    "aa",
        Age:     1,
        Address: new(int),
      Data:    []int{1, 2, 3},
    }

   fmt.Println(reflect.DeepEqual(a, b))
}

распечатать:

true

Так как же Reflect.DeepEqual сравнивает переменные?

reflect.DeepEqual

Функция DeepEqual используется для определения того, являются ли два значения глубоко согласованными. Конкретные правила сравнения следующие:

  • Ценности разных типов никогда не бывают глубоко равными
  • Два массива имеют одинаковую глубину, когда соответствующие глубины элементов двух массивов равны.
  • Когда все поля двух одинаковых структур соответствуют одной и той же глубине, глубины двух структур равны
  • Когда обе функции равны нулю, две функции имеют одинаковую глубину, в противном случае они не равны (одна и та же функция также не равна)
  • Когда глубины истинных значений двух интерфейсов равны, глубины двух интерфейсов равны
  • Сравнение карт должно одновременно отвечать следующим требованиям.
    • Обе карты равны нулю или ни одна из них не равна нулю, а длины должны быть равны
    • Один и тот же объект карты или все ключи должны соответствовать одному и тому же
    • Значение, соответствующее карте, также должно иметь одинаковую глубину.
  • Указатель, удовлетворяющий одному из следующих условий, равен глубине
    • Два указателя удовлетворяют оператору go ==
    • Значения, на которые указывают два указателя, глубоко равны
  • Нарезая, вам необходимо одновременно выполнить следующие пункты, чтобы они были равными по глубине
    • Оба среза равны нулю или ни один из них не равен нулю и имеют одинаковую длину
    • Первая позиция, на которую указывают базовые данные двух срезов, должна быть одинаковой или базовые элементы должны иметь одинаковую глубину.
    • Примечание. Пустой срез не имеет такой же глубины, как нулевой срез.
  • Значения других типов (числа, логические значения, строки, каналы) глубоко равны, если они удовлетворяют оператору go ==. Имейте в виду, что не все значения глубоко равны сами себе, такие как функции и вложенные структуры, массивы и т. д., которые содержат эти значения.

Можно ли сравнивать два экземпляра разных структур?

"в заключении": Сопоставимо или несопоставимо

Сравнение можно провести с помощью приведения:

type T2 struct {
    Name  string
    Age   int
    Arr   [2]bool
    ptr   *int
}

type T3 struct {
    Name  string
    Age   int
    Arr   [2]bool
    ptr   *int
}

func main() {
    var ss1 T2
    var ss2 T3
    // Cannot use 'ss2' (type T3) as type T2 in assignment
    //ss1 = ss2     // 不同结构体之间是不可以赋值的
    ss3 := T2(ss2)
    fmt.Println(ss3==ss1) // true
}

Если переменная-член содержит несопоставимые переменные-члены, даже если она может быть приведена, ее нельзя сравнивать

type T2 struct {
    Name  string
    Age   int
    Arr   [2]bool
    ptr   *int
    map1  map[string]string
}

type T3 struct {
    Name  string
    Age   int
    Arr   [2]bool
    ptr   *int
    map1  map[string]string
}

func main() {
    var ss1 T2
    var ss2 T3
    
    ss3 := T2(ss2)
    fmt.Println(ss3==ss1)   // 含有不可比较成员变量
}

Ошибка компиляции:

# command-line-arguments
./test.go:28:18: invalid operation: ss3 == ss1 (struct containing map[string]string cannot be compared)

В: Можно ли использовать структуру в качестве ключа карты?

структура должна быть сопоставима, прежде чем ее можно будет использовать в качестве ключа, иначе при компиляции будет сообщено об ошибке

type T1 struct {
    Name  string
    Age   int
    Arr   [2]bool
    ptr   *int
    slice []int
    map1  map[string]string
}

type T2 struct {
    Name string
    Age  int
    Arr  [2]bool
    ptr  *int
}

func main() {
    // n := make(map[T2]string, 0) // 无报错
    // fmt.Print(n)                // map[]

    m := make(map[T1]string, 0)
    fmt.Println(m) // invalid map key type T1
}

Это то, чем я хочу поделиться с вами сегодня.Если у вас есть какие-либо вопросы, пожалуйста, оставьте сообщение дяде на заднем плане, обратите вниманиедядя говорит код, увидимся в следующий раз~

Справочная документация:

  1. https://studygolang.com/pkgdoc
  2. https://studygolang.com/articles/12944?fr=sidebar