обнаружение nil в Go



Я вижу много кода в Go для обнаружения nil, например:



if err != nil { 
// handle the error
}


, у меня есть структура, как это:

type Config struct {
host string
port float64
}


и config-это экземпляр Config, когда я делаю:



if config == nil {
}


есть ошибка компиляции, говоря:
не удается преобразовать nil в тип Config

619   5  

5 ответов:

компилятор указывает на ошибку для вас, вы сравниваете экземпляр структуры и nil. Они не одного типа, поэтому он считает это недопустимым сравнением и кричит на вас.

что вы хотите сделать здесь, это сравнить указатель на ваш экземпляр конфигурации с нулем, что является допустимым сравнением. Для этого вы можете использовать golang новая встроенные или инициализировать указатель на него:

config := new(Config) // not nil

или

config := &Config{host: myhost.com, port: 22} // not nil

или

var config *Config // nil

тогда вы сможете проверить, если

if config == nil {
    // then
}

в дополнение к Oleiade, см. спецификация на нулевые значения:

когда память выделена для хранения значения, либо через объявление или вызов make или new, и явная инициализация не предусмотрена, памяти присваивается инициализация по умолчанию. каждому элементу такого значения присваивается нулевое значение для его типа: false для булевых значений, 0 для целых чисел, 0.0 для поплавков, "" для строк и nil для указателей, функций, интерфейсов, срезов, каналы, и карты. эта инициализация выполняется рекурсивно, поэтому, например, каждый элемент массива структур будет иметь свои поля обнулены, если не указано значение.

Как видите, nil - это не нулевое значение для каждого типа, а только для указателей, функций, интерфейсов, срезов, каналов и карт. Вот почему config == nil ошибка и &config == nil нет.

чтобы проверить, является ли ваша структура неинициализированной, вам нужно будет проверить каждый член для своих соответствующее нулевое значение (например,host == "",port == 0 и т. д.) или иметь личное поле, которое устанавливается методом внутренней инициализации. Пример:

type Config struct {
    Host string  
    Port float64
    setup bool
}

func NewConfig(host string, port float64) *Config {
    return &Config{host, port, true}
}

func (c *Config) Initialized() bool { return c != nil && c.setup }

Я создал некоторый пример кода, который создает новую переменную, используя различные способы, которые я могу придумать. Похоже, что первые 3 способа создают значения, а последние два создают ссылки.

package main

import "fmt"

type Config struct {
    host string
    port float64
}

func main() {
    //value
    var c1 Config
    c2 := Config{}
    c3 := *new(Config)

    //reference
    c4 := &Config{}
    c5 := new(Config)

    fmt.Println(&c1 == nil)
    fmt.Println(&c2 == nil)
    fmt.Println(&c3 == nil)
    fmt.Println(c4 == nil)
    fmt.Println(c5 == nil)

    fmt.Println(c1, c2, c3, c4, c5)
}

выходы:

false
false
false
false
false
{ 0} { 0} { 0} &{ 0} &{ 0}

вы также можете проверить, как struct_var == (struct{}). Это не позволяет сравнивать с нулем, но он проверяет, если он инициализирован или нет. Будьте осторожны при использовании этого метода. Если ваша структура может иметь нулевые значения для всех своих полях вы не будете иметь большое время.

package main

import "fmt"

type A struct {
    Name string
}

func main() {
    a := A{"Hello"}
    var b A

    if a == (A{}) {
        fmt.Println("A is empty") // Does not print
    } 

    if b == (A{}) {
        fmt.Println("B is empty") // Prints
    } 
}

http://play.golang.org/p/RXcE06chxE

The язык спецификаций упоминает поведение операторов сравнения:

операторы сравнения

в любом сравнении первый операнд должен быть присвоен типу второго операнда, или наоборот.


Назначаемость

значение x присваивается переменной типа T ("x присваивается Т") в любом из этих случаев:

  • тип x идентичен T.
  • X тип V и T имеют идентичные базовые типы, и по крайней мере один из V или T не является именованным типом.
  • T-Тип интерфейса, а x реализует T.
  • x-значение двунаправленного канала, T-тип канала, X-тип V и T имеют одинаковые типы элементов, и по крайней мере один из V или T не является именованный тип.
  • x-предварительный идентификатор nil, а T-указатель, функция, срез, карта, канал, или тип интерфейса.
  • x-нетипизированная константа, представимая значением типа T.

Comments

    Ничего не найдено.