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


110

구조체를 정의합니다 ...

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

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

session = Session{};

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

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

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


4
Session {}은 "빈"세션이 아닙니다. 각 필드가 0 값으로 초기화됩니다.
Paul Hankin

답변:


177

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

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

놀이터 예

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

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

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

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

4
@kristen 포인터를 역 참조하고 비교합니다. 경우 sessionnil이 아닌 것입니다 *Session, 다음 사용합니다 if (Session{} == *session {.
Muffin Top

3
그래서 struct containing []byte cannot be compared내 구조체에는 바이트 슬라이스가 포함되어 있기 때문에 오류가 발생 합니다.
그 뿐이었다

14
@Nevermore 대답은 비교 가능한 필드가있는 구조체에 적용됩니다. 구조체에 [] byte와 같은 비교할 수없는 값이 포함 된 경우 모든 필드를 테스트하는 코드를 작성하거나 다른 답변에 설명 된대로 reflect 패키지를 사용해야합니다.
Muffin Top

2
@Nevermore에서 언급했듯이 ==슬라이스 필드와의 비교는 실패합니다. 이러한 구조체를 비교하려면 다음 중 하나를 사용하거나 reflect.DeepEqual여기에 설명 된 것과 같이 더 전문화 된 것을 고려하십시오. stackoverflow.com/questions/24534072/…
asgaines

fmt.Println (session == Session {})에서 시도했을 때 "[if condition]에서 모호함을 구문 분석"하여 하루를 절약했습니다. 감사합니다.
Franva

37

다음은 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)
}

좋은 대답입니다. 고마워, icza!
Evgeny Goldin

멋진 대답입니다! 나는 마지막 선택을 따르는 것이 꽤 관용적이라고 생각합니다.
DeivinsonTejeda

19

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

2
reflect.DeepEqual을 사용하는 것은 매우 깨끗한 솔루션이지만 처리 시간이 더 걸리는지 궁금합니다. 나는 그것이 모든 필드를 비교하고 있다고 가정하고 새로운 가져 오기를 소개합니다.
thurt

4

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

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

놀이터를 확인하십시오 .

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


0

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

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

놀이터 예


0

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

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

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

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


-1

같은 아마 뭔가

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")
    } 
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.