[go] Go의 무 탐지

Go에서 다음과 같이 nil을 감지하는 많은 코드가 있습니다.

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

그러나 다음과 같은 구조체가 있습니다.

type Config struct {
    host string
    port float64
}

그리고 config는 Config의 인스턴스입니다.

if config == nil {
}

컴파일 오류가 있습니다 : nil을 Config 유형으로 변환 할 수 없습니다.



답변

컴파일러가 오류를 가리키고 있습니다. 구조 인스턴스와 nil을 비교하고 있습니다. 그것들은 같은 타입이 아니기 때문에 그것을 잘못된 비교로 간주하고 당신에게 소리칩니다.

여기서하려는 것은 구성 인스턴스에 대한 포인터를 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 호출을 통해 값을 저장하기 위해 메모리가 할당되고 명시적인 초기화가 제공되지 않으면 메모리에 기본 초기화가 제공됩니다. 이러한 값의 각 요소는 해당 유형의 0 값으로 설정됩니다. 부울의 경우 false, 정수의 경우 0, 부동 소수점의 경우 0.0, 문자열의 경우 “”, 포인터, 함수, 인터페이스, 슬라이스, 채널 및 맵의 경우 nil. 이 초기화는 재귀 적으로 수행되므로 예를 들어 값을 지정하지 않으면 구조체 배열의 각 요소에는 필드가 0이됩니다.

보시다시피, nil모든 유형의 0 값이 아니라 포인터, 함수, 인터페이스, 슬라이스, 채널 및 맵의 경우에만 0입니다. 이것이 왜 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 }


답변

내가 생각할 수있는 다양한 방법을 사용하여 새 변수를 만드는 샘플 코드를 만들었습니다. 처음 세 가지 방법으로 값을 만들고 마지막 두 가지 방법으로 참조를 만듭니다.

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{}). 이를 통해 nil과 비교할 수는 없지만 초기화되었는지 여부를 확인합니다. 이 방법을 사용하는 동안주의하십시오. 구조체가 모든 필드에 대해 0 값 을 가질 수 있다면 좋은 시간이 없습니다.

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


답변

언어 스펙 비교 연산자 ‘행동을 언급한다 :

비교 연산자

비교할 때, 첫 번째 피연산자는 두 번째 피연산자의 유형에 지정 가능하거나 그 반대로 지정 가능해야합니다.


할당 가능성

다음과 같은 경우 x 값은 T 유형의 변수에 할당 가능합니다 ( “x는 T에 할당 가능”).

  • x의 유형은 T와 동일합니다.
  • x의 유형 V와 T는 동일한 기본 유형을 가지며 V 또는 T 중 적어도 하나는 명명 된 유형이 아닙니다.
  • T는 인터페이스 유형이며 x는 T를 구현합니다.
  • x는 양방향 채널 값이고, T는 채널 유형이며, x의 유형 V와 T는 동일한 요소 유형을 가지며 V 또는 T 중 적어도 하나는 명명 된 유형이 아닙니다.
  • x는 미리 선언 된 식별자 nil이고 T는 포인터, 함수, 슬라이스, 맵, 채널 또는 인터페이스 유형입니다.
  • x는 유형 T의 값으로 표현할 수있는 형식화되지 않은 상수입니다.

답변

Go 1.13 이상에서는 패키지로 Value.IsZero제공되는 방법 을 사용할 수 있습니다 reflect.

if reflect.ValueOf(v).IsZero() {
    // v is zero, do something
}

기본 유형 외에도 Array, Chan, Func, Interface, Map, Ptr, Slice, UnsafePointer 및 Struct에서도 작동합니다. 참고 이를 참조하십시오.


답변