스위프트 상수 : Struct 또는 Enum


80

둘 중 어느 것이 상수를 정의하는 것이 더 나은지 잘 모르겠습니다. 구조체 또는 열거 형. 구조체는 사용할 때마다 복사됩니까? static let상수 가있는 구조체에 대해 생각할 때 제 생각에는 항상 복사 될 것이라는 것은 의미가 없습니다. 그러나 그것이 복사되지 않으면 내가 무엇을 가져가는 것이 중요하지 않습니까?

구조체 또는 열거 형을 선택하면 어떤 이점이 있습니까?

Francisco는 Struct를 사용한다고 말합니다.

Ray Wenderlich는 Enum을 사용한다고 말합니다. 그러나 나는 정당성이 부족합니다.


3
링크 된 기사에 정당화가 있습니다. "대소 문자없는 열거를 사용하는 이점은 실수로 인스턴스화 할 수없고 순수한 네임 스페이스로 작동한다는 것입니다."
Martin R

논리적으로 들리는군요. 따라서 내 사례의 90 %에서 열거 형을 사용해야합니다. 그리고 무언가를 인스턴스화하거나 변수가 될 필요가있는 즉시 구조체를 사용합니다. 옳은?
Paixsn

2
그것들을 사용하는 클래스에서 정의하지 않는 이유는 무엇입니까? 모든 상수를 하나의 구조에 배치해야하는 이유는 무엇입니까? 확장자를 사용하는 경우에도 하나의 파일에 저장할 수 있습니다. enum과 struct 사이를 결정하는 경우 아키텍처 관점에서 어느 것도 말하지 않습니다.
Sulthan

프로젝트의 대부분에 포함 할 수있는 프레임 워크가 필요하기 때문입니다. 나는 그들 모두에 동일한 상수가 필요할 것입니다. 그래서 여러 번 쓰고 싶지 않습니다.
Paixsn

1
@SnowN 나는 상수에 반대하지는 않지만 공통점이 없다면 하나의 공통 구조 / 열거 형에 모두 넣을 필요가 없다고 말하고 있습니다.
Sulthan

답변:


130

구조체와 열거 모두 작동합니다. 예를 들어, 둘 다

struct PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

enum PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

작동하고 정적 속성을 정의합니다 PhysicalConstants.speedOfLight.

Re : 구조체는 사용할 때마다 복사됩니까?

struct및 둘 다 enum값 유형이므로 열거 형에도 적용됩니다. 하지만 여기서는 값을 전혀 만들 필요가 없기 때문에 관련 이 없습니다. 정적 속성 ( 유형 속성 이라고도 함 )은 해당 유형의 인스턴스가 아니라 유형 자체의 속성입니다.

Re : 구조체 또는 열거 형을 선택하면 어떤 이점이 있습니까?

링크 된 문서 에서 언급했듯이 :

대소 문자가없는 열거를 사용하는 이점은 실수로 인스턴스화 할 수없고 순수 네임 스페이스로 작동한다는 것입니다.

따라서 구조의 경우

let foo = PhysicalConstants()

유형의 (쓸모없는) 값을 생성 PhysicalConstants하지만 대소 문자가없는 열거의 경우 컴파일에 실패합니다.

let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers

대소 문자가없는 열거 형을 사용할 수없는 switch 문과 관련된 특별한 경우가 하나 있습니다. 토론 및 가능한 해결 방법은 내 대답을 참조하십시오.
Tim Fuqua

6
사소한 추가 : 예제에 추가 private init() {}하면 Struct실수로 즉석에서 인스턴스화 할 수 없다는 "장점"도 유지됩니다. (물론이 "장점"는의 확장에 초기화를 포함하여 몇 가지 DEV-사용자에 의해 피할 수 Struct:하지만 경우에 우리가 어떤 이유로 거라고는 사용을 선호 Struct라기보다는 "순수 네임 스페이스"방식으로 enum다음, 개인 이니셜 라이저는 인스턴스로 사용하지 않는 좋은 보호 장치가 될 수 있습니다).
dfrib

... 그리고 나는 바로이 지점이 아래의 다른 답변에서 (일종의) 언급되었음을 깨달았습니다 (동일 파일 개인 문제가 더 이상 Swift 3에 존재하지 않지만 언급되었지만).
dfrib

그것은 매우 유용하지 않은 이점입니다. 나는 실제로 struct Constants static let speedOfLight = 300vs 비교를 위해 여기에 왔습니다 enum Constants enum Light : Int case speed = 300. 당신의 대답에서도 비교할 수 있습니까? 아니면 그 비교에 대한 또 다른 답이 있습니까?
Honey

@Honey : 그건 다른 질문입니다. 이것은 (내가 이해했듯이) 네임 스페이스 를 제공하는 것에 관한 것 입니다. 정적 상수는 구조체 내부 또는 열거 형 내부에 정의 할 수 있습니다. 다른 유형을 가질 수 있으며 동일한 값을 가진 여러 상수를 가질 수 있습니다. – 열거 의 경우 는 동일한 유형의 (상호 구별되는) 값을 정의합니다.
Martin R

17

짧은 대답은 다음과 같습니다. 상수가 고유해야합니까? 그런 다음이를 적용하는 열거 형을 사용합니다.

동일한 값을 포함하기 위해 여러 다른 상수를 사용하고 싶으십니까 (종종 명확성을 위해 유용함)? 그런 다음이를 허용하는 구조체를 사용하십시오.


1
나는 그가 항상 쓸 필요가 있었기 때문에 개별 케이스를 사용하지 않을 것이라고 생각합니다StaticVars.pi.rawValue
Michael

8

둘 사이의 한 가지 차이점은 열거 형이 할 수없는 곳에서 구조체를 인스턴스화 할 수 있다는 것입니다. 따라서 상수 만 사용해야하는 대부분의 시나리오에서는 혼동을 피하기 위해 열거 형을 사용하는 것이 가장 좋습니다.

예를 들면 :

struct Constants {
    static let someValue = "someValue"
}

let _ = Constants()

위의 코드는 여전히 유효합니다.

열거 형을 사용하는 경우 :

enum Constants {
    static let someValue = "someValue"
}

let _ = Constants() // error

위의 코드는 유효하지 않으므로 혼동을 피하십시오.


6

Xcode 7.3.1 및 Swift 2.2 사용

Martin R에 동의하고 Ray Wenderlich 스타일 가이드는 enum이 순수한 네임 스페이스이기 때문에 거의 모든 사용 사례에서 더 좋다는 점을 지적하지만, struct트럼프를 사용하는 곳이 한 곳 enums있습니다.

Switch 문

구조체 버전부터 시작하겠습니다.

struct StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

구조체를 사용하면 Matched StaticVars.someString.

이제 (키워드 만 변경하여 대소 문자를 구별 열거 버전을 고려할 수 struct에를 enum)

enum StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

case StaticVars.someString:줄 의 switch 문에서 컴파일 시간 오류가 발생하는 것을 알 수 있습니다. 오류는 Enum case 'someString' not found in type 'String'입니다.

정적 속성을 대신 형식을 반환하는 클로저로 변환하는 의사 해결 방법이 있습니다.

따라서 다음과 같이 변경합니다.

enum StaticVars {
    static let someString = { return "someString" }
}

switch "someString" {
case StaticVars.someString(): print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

이제는 함수이므로 case 문에 괄호가 필요합니다.

단점은 이제 함수로 만들었으므로 호출 될 때마다 실행된다는 것입니다. 따라서 String또는 과 같은 단순한 기본 유형이라면 Int그렇게 나쁘지 않습니다. 본질적으로 계산 된 속성입니다. 계산해야하는 상수이고 한 번만 계산하려는 경우 다른 속성으로 계산하고 이미 계산 된 값을 클로저에 반환하는 것을 고려하십시오.

기본 이니셜 라이저를 개인용으로 재정의 할 수도 있습니다. 그러면 대 / 소문자가없는 열거 형과 동일한 종류의 컴파일 시간 오류를 얻을 수 있습니다.

struct StaticVars {
    static let someString = "someString"
    private init() {}
}

그러나 이것으로 구조체의 선언을 자체 파일에 넣기를 원할 것입니다. 의 인스턴스 StaticVars이지만 클래스 파일 외부에서는 의도 한대로 작동합니다. 그러나 그것은 당신의 부름입니다.


3
분명히이 문제는 해결되었습니다. "케이스없는 열거 형 버전"은 Xcode 8 베타 6에서 예상대로 컴파일 및 실행됩니다.
Martin R

1
바로! "인스턴스화 없음"이점을 위해 대소 문자가없는 열거 형을 사용하는 것을 정말 좋아합니다. 또한 Xcode 버전 정보로 게시물을 시작하게되어 기쁩니다. 그렇지 않으면 "내 컴퓨터에서 작동"문제가있을 수 있습니다.
Tim Fuqua

@MartinR Xcode 8에서 "baseless enum"의 경우가 정렬되었다고 지적했듯이 이제 "struct"와 "enum"에서 정적 let을 선언하는 차이점은 무엇입니까?
G.Abhisek

@ G.Abhisek : 내 대답에서 대답하려고했습니다. 대소 문자가없는 열거 형을 사용하면 해당 유형의 (쓸모없는) 인스턴스를 만들 수 없습니다. 상수 자체에 대해서는 전혀 차이가 없습니다.
Martin R

@MartinR 따라서 구조체를 통해 액세스 할 때 불필요하게 인스턴스를 생성하는 반면 enum의 경우 네임 스페이스 역할을합니다.
G.Abhisek

4

에서 결합 프레임 워크, 애플은 네임 스페이스에 대한 열거 형을 선호하는 선택했다.

enum Publishers

게시자 역할을하는 유형의 네임 스페이스입니다.

enum Subscribers

구독자 역할을하는 유형의 네임 스페이스입니다.

enum Subscriptions

구독과 관련된 기호의 네임 스페이스입니다.

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