detección nula en Go


Veo mucho código en Go para detectar nil, así:

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

Sin embargo, tengo una estructura como esta:

type Config struct {
    host string  
    port float64
}

Y config es una instancia de Config, cuando lo hago:

if config == nil {
}

Hay un error de compilación, diciendo: no se puede convertir nil a type Config

 106
Author: John Weldon, 2013-11-27

5 answers

El compilador está apuntando el error a usted, usted está comparando una instancia de estructura y nil. No son del mismo tipo, así que lo considera una comparación inválida y te grita.

Lo que quiere hacer aquí es comparar un puntero a su instancia de configuración con nil, que es una comparación válida. Para hacer eso, puede usar el golang nuevo incorporado, o inicializar un puntero a él:

config := new(Config) // not nil

O

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

O

var config *Config // nil

Entonces usted será capaz de comprobar si

if config == nil {
    // then
}
 129
Author: Oleiade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-22 01:42:32

Además de Oleiade, ver la especificación sobre valores cero :

Cuando se asigna memoria para almacenar un valor, ya sea a través de una declaración o una llamada de make o new, y no se proporciona una inicialización explícita, la memoria recibe una inicialización predeterminada. Cada elemento de tal valor se establece en el valor cero para su tipo: false para booleanos, 0 para enteros, 0.0 para flotadores, "" para cadenas, y nil para punteros, funciones, interfaces, sectores, canales y mapas. Esta inicialización se realiza recursivamente, por lo que, por ejemplo, cada elemento de una matriz de estructuras tendrá sus campos a cero si no se especifica ningún valor.

Como puede ver, nil no es el valor cero para cada tipo, sino solo para punteros, funciones, interfaces, sectores, canales y mapas. Esta es la razón por la que config == nil es un error y &config == nil no lo es.

Para verificar si su estructura no está inicializada, tendría que verificar que cada miembro valor cero respectivo (por ejemplo, host == "", port == 0, sucesivamente.) o tener un campo privado que se establece mediante un método de inicialización interna. Ejemplo:

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 }
 50
Author: nemo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-06 15:18:11

He creado algunos algunos código de ejemplo que crea una nueva variable utilizando una variedad de maneras que puedo pensar. Parece que las primeras 3 formas crean valores, y las dos últimas crean referencias.

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)
}

Que produce:

false
false
false
false
false
{ 0} { 0} { 0} &{ 0} &{ 0}
 14
Author: Elgs Qian Chen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-28 17:53:46

También puedes marcar como struct_var == (struct{}). Esto no le permite comparar con nil, pero comprueba si está inicializado o no. Tenga cuidado al usar este método. Si su estructura puede tener valores cero para todos sus campos, no tendrá un gran tiempo.

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

 5
Author: Thellimist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-22 02:02:21

La especificación del lenguaje menciona los comportamientos de los operadores de comparación:

Operadores de comparación

En cualquier comparación, el primer operando debe ser asignable al tipo del segundo operando, o viceversa.


Asignabilidad

Un valor x es asignable a una variable de tipo T ("x es asignable a T") en cualquiera de estos casos:

  • el tipo de x es idéntico a T.
  • tipo V y T de X tienen tipos subyacentes idénticos y al menos uno de V o T no es un tipo con nombre.
  • T es un tipo de interfaz y x implementa T.
  • x es un valor de canal bidireccional, T es un tipo de canal, el tipo de X V y T tienen tipos de elementos idénticos, y al menos uno de V o T no es un tipo con nombre.
  • x es el identificador predeclarado nil y T es un puntero, función, segmento, mapa, canal o tipo de interfaz.
  • x es una constante sin tipo representable por un valor de tipo T.
 3
Author: supei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-12 08:07:31