[struct] 빈 구조체를 확인하는 방법은 무엇입니까?

구조체를 정의합니다 …

type Session struct {
    playerId string
    beehive string
    timestamp time.Time
}

때로는 빈 세션을 할당합니다 (nil이 불가능하기 때문에)

session = Session{};

그런 다음 비어 있는지 확인하고 싶습니다.

if session == Session{} {
     // do stuff...
}

분명히 이것은 작동하지 않습니다. 어떻게 작성합니까?



답변

모든 필드가 비교 가능 하므로 ==를 사용하여 0 값 복합 리터럴과 비교할 수 있습니다 .

if (Session{}) == session  {
    fmt.Println("is zero value")
}

놀이터 예

구문 분석의 모호성 때문에 if 조건에서 복합 리터럴을 괄호로 묶어야합니다.

==위 의 사용은 모든 필드가 비교할 수 있는 구조체에 적용됩니다 . 구조체에 비교할 수없는 필드 (슬라이스, 맵 또는 함수)가 포함 된 경우 필드를 0 값과 하나씩 비교해야합니다.

전체 값을 비교하는 대안은 유효한 세션에서 0이 아닌 값으로 설정해야하는 필드를 비교하는 것입니다. 예를 들어 유효한 세션에서 플레이어 ID가! = “”여야하는 경우

if session.playerId == "" {
    fmt.Println("is zero value")
}


답변

다음은 3 가지 추가 제안 또는 기술입니다.

추가 필드 포함

추가 필드를 추가하여 구조체가 채워 졌는지 또는 비어 있는지 알 수 있습니다. 나는 의도적으로 이름 ready이 아닌 emptya의 영점이 있기 때문 bool입니다 false, 당신이 만들 그렇다면 같은 새로운 구조체 Session{}ready필드가 자동으로 될 것입니다 false그리고 당신에게 진실을 말할 것이다 : 구조체가 없습니다 아직 (비어의) 준비가되어 있음.

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}

구조체를 초기화 할 때로 설정 ready해야 true합니다. 당신의 isEmpty()당신은 단지 테스트 할 수 있기 때문에 (당신이 원하는 경우에 당신이 하나를 만들 수 있지만) 방법은 더 이상 필요하지 않은 ready필드 자체를.

var s Session

if !s.ready {
    // do stuff (populate s)
}

bool구조체가 커지거나 비교할 수없는 필드 (예 : 슬라이스 map및 함수 값) 가 포함 된 경우이 하나의 추가 필드의 중요성이 증가 합니다.

기존 필드의 0 값 사용

이는 이전 제안과 유사하지만 구조체가 비어 있지 않을 때 유효하지 않은 것으로 간주되는 기존 필드의 0 값을 사용합니다 . 이것의 유용성은 구현에 따라 다릅니다.

예를 들어 귀하의 예제 playerId에서 비어 string ""있을 수 없다면 다음과 같이 구조체가 비어 있는지 테스트하는 데 사용할 수 있습니다.

var s Session

if s.playerId == "" {
    // do stuff (populate s, give proper value to playerId)
}

isEmpty()경우이 검사는 구현에 따라 다르기 때문에이 검사를 메서드에 통합하는 것이 좋습니다.

func (s Session) isEmpty() bool {
    return s.playerId == ""
}

그리고 그것을 사용 :

if s.isEmpty() {
    // do stuff (populate s, give proper value to playerId)
}

구조체에 포인터 사용

두 번째 제안은 구조체에 대한 포인터를 사용하는 것입니다 : *Session. 포인터는 nil값 을 가질 수 있으므로 테스트 할 수 있습니다.

var s *Session

if s == nil {
    s = new(Session)
    // do stuff (populate s)
}


답변

reflect.deepEqual 을 사용하면 특히 구조체 내부에 맵이있는 경우 에도 작동합니다 .

package main

import "fmt"
import "time"
import "reflect"

type Session struct {
    playerId string
    beehive string
    timestamp time.Time
}

func (s Session) IsEmpty() bool {
  return reflect.DeepEqual(s,Session{})
}

func main() {
  x := Session{}
  if x.IsEmpty() {
    fmt.Print("is empty")
  }
}


답변

구조체에 대한 포인터를 사용하면 변수를 역 참조하고 빈 구조체에 대한 포인터와 비교하지 않아야합니다.

session := &Session{}
if (Session{}) == *session {
    fmt.Println("session is empty")
}

놀이터를 확인하십시오 .

또한 여기에서 포인터 조각 인 속성을 보유한 구조체는 동일한 방식으로 비교할 수 없음을 알 수 있습니다.


답변

다른 답변에 대한 대안으로, case대신 문을 통해 수행하는 경우 원래 의도 한 방식과 유사한 구문 으로이 작업을 수행 할 수 있습니다 if.

session := Session{}
switch {
case Session{} == session:
    fmt.Println("zero")
default:
    fmt.Println("not zero")
}

놀이터 예


답변

오늘 같은 문제를 다루었 기 때문에 간단히 추가했습니다.

Go 1.13에서는 새로운 isZero()방법 을 사용할 수 있습니다 .

if reflect.ValueOf(session).IsZero() {
     // do stuff...
}

성능과 관련하여 이것을 테스트하지는 않았지만 비교하는 것보다 빠르다고 생각합니다 reflect.DeepEqual().


답변

같은 아마 뭔가

package main

import "fmt"
import "time"

type Session struct {
    playerId string
    beehive string
    timestamp time.Time
}

func (s Session) Equal(o Session) bool {
   if(s.playerId != o.playerId) { return false }
   if(s.beehive != o.beehive) { return false }
   if(s.timestamp != o.timestamp) { return false }
   return true
}

func (s Session) IsEmpty() bool {
    return s.Equal(Session{})
}

func main() {
    x := Session{}
    if x.IsEmpty() {
       fmt.Print("is empty")
    }
}