프로그래밍Go 개발자

map[string]struct{}는 Go에서 set으로 어떻게 작동하며 이러한 적용의 특징은 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

질문의 역사:

Go는 기본적으로 Set 구조체를 제공하지 않지만, 고유한 요소와 작업해야 하는 경우가 자주 발생합니다. 최적의 구조체는 map[string]struct{}로, 여기서 키는 요소이며 빈 구조체는 "존재 마크"로 사용됩니다. 이는 빠른 membership 테스트를 위한 일반적인 패턴입니다.

문제:

내장된 Set이 없기 때문에 초보자들은 고유한 컬렉션을 올바르게 구현하는 것이 어렵다고 느낍니다. 또한, struct{}가 bool이나 int보다 값으로서 더 효율적인 이유를 이해할 필요가 있습니다.

해결책:

Go에서 Set을 구현하기 위해서는 map[string]struct{}를 사용합니다. 빈 구조체 struct{}는 메모리를 요구하지 않으며(zero-sized), map은 빠른 접근을 보장합니다. 예:

set := make(map[string]struct{}) set["foo"] = struct{}{} if _, ok := set["foo"]; ok { fmt.Println("존재") } delete(set, "foo")

주요 특징:

  • struct{}는 0 바이트를 차지 — 경제적인 구현
  • map은 O(1) 키 접근을 제공합니다
  • 요소 중복이 없으며, Set의 의미가 쉽게 구현됩니다

반대 질문.

왜 slice/배열을 값으로 사용할 수 없나요?

slice/배열은 set으로 사용할 경우 요소 검색에 상수 시간 복잡도를 제공하지 않으며, 모든 값을 순회해야 하므로 느립니다.

map[string]struct{}와 map[string]bool의 차이는 무엇인가요?

map[string]bool은 더 많은 메모리를 차지합니다: 각 키마다 bool을 저장하는 반면, struct{}는 빈 타입으로 아무것도 할당하지 않습니다.

set := map[string]bool{"foo": true}

struct{} 대신 int를 사용할 수 있나요?

가능하지만, int는 항상 메모리를 차지합니다. struct{}는 만능입니다: "마크"(존재) 역할만 필요하다면 더 좋습니다.

set := map[string]int{"foo": 1} // 하지만 (키 -> 숫자)를 저장함

전형적인 오류 및 안티 패턴

  • 필요 없이 bool이나 int를 값으로 사용
  • 요소 존재 여부를 확인하기 위해 slice를 사용 (검사를 느리게 함)
  • delete를 통해 요소를 제거하는 것을 잊음

실생활 예

부정적인 경우

무지로 인해 고유한 IP 주소 집합을 위해 map[string]bool이 지정되었습니다. 결과적으로 수백만 개의 주소에서 메모리 사용량이 struct{}에 비해 두 배로 증가했습니다.

장점:

  • 의미상 명확함 (true == 존재)

단점:

  • 성능 저하
  • 메모리 사용 증가

긍정적인 경우

프로젝트에서 고유한 이메일을 저장하기 위해 map[string]struct{}를 사용했습니다. 부담이 줄어들고 더 빠르게 작동했으며, 값에 대해 거의 메모리를 사용하지 않았습니다.

장점:

  • 최소한의 오버헤드
  • 많은 요소에서의 성능

단점:

  • 초보자에게 덜 명확하며 코드에 주석이 필요함