관련 유형의 매거진을 가진 원시 값 초기화 구조기
스위프트에서 매거(Enums)는 우아한 구조화된 정보의 방식이다.때때로 당신은 원시 값(raw values)을 통해 매거진을 구성해야 한다는 것을 발견할 수 있다. 왜냐하면 이 값들은 일부분에 저장될 수 있기 때문이다. 예를 들어
NSUserDefaults
:enum Device: String {
case Phone, Tablet, Watch
}
let aDevice = Device(rawValue: "Phone")
print(aDevice)
// : Optional(main.Device.Phone)
문제.
그러나 매거진에서 관련 값 (associated values) 을 사용하면 이 방식은 효력을 상실합니다.예를 들어 이런 매거:
enum Example {
case Factory(workers: Int)
case House(street: String)
}
이 매거진 두 멤버
case
인 팩토리와 하우스는 서로 다른 관련 유형(workers
이 정형street
이 문자열)이기 때문에 스와프는 Example
의 실례를 구성할 수 없다.Example
각 구성원의 호출은 서로 다른 유형의 매개 변수를 필요로 하기 때문에 이런 방법은 통용할 수 없다.그러나 모든 구성원의 연관 유형이 같아도 이런 방법은 소용없다.
enum Device {
case Phone(name: String, screenSize: CGSize)
case Watch(name: String, screenSize: CGSize)
case Tablet(name: String, screenSize: CGSize)
}
이 예에서 모든 관련 유형(associated types)은 똑같다. 사실상 여러 가지 방식으로 문제를 설명할 수 있지만
Device
매거진으로 간단명료하게 설명할 수 있다는 것을 발견했다. 각 Device
구성원의 관련 유형이 똑같아도 원시 값 같은 것을 사용하여 그것을 만들고 정확한 유형을 얻을 수 없다는 것이다.정확한 실례를 만들기 위해 일치해야 합니다.import Foundation
enum Device {
case Phone(name: String, screenSize: CGSize)
case Watch(name: String, screenSize: CGSize)
case Tablet(name: String, screenSize: CGSize)
static func fromDefaults(rawValue: String, name: String, screenSize: CGSize) -> Device? {
switch rawValue {
case "Phone": return Device.Phone(name: name, screenSize: screenSize)
case "Watch": return Device.Watch(name: name, screenSize: screenSize)
case "Tablet": return Device.Tablet(name: name, screenSize: screenSize)
default: return nil
}
}
}
let b = Device.fromDefaults("Phone", name: "iPhone SE", screenSize: CGSize(width: 640, height: 1136))
print(b)
// : Optional(main.Device.phone("iPhone SE", (640.0, 1136.0)))
이것은 보기에는 괜찮은 것 같지만, 이 코드들은 확실히 좀 불필요하다.일단 당신이 만들어야 할 매거 중 세 개 이상의 매거 구성원이나 두 가지 이상의 관련 유형이 있다면 일은 곧 통제력을 잃게 될 것이다.
enum Vehicle {
case Car(wheels: Int, capacity: Int, weight: Int, length: Int, height: Int, width: Int, color: Int, name: Int, producer: Int, creation: NSDate, amountOfProducedUnits: Int)
case Ship(wheels: Int, capacity: Int, weight: Int, length: Int, height: Int, width: Int, color: Int, name: Int, producer: Int, creation: NSDate, amountOfProducedUnits: Int)
case Yacht(wheels: Int, capacity: Int, weight: Int, length: Int, height: Int, width: Int, color: Int, name: Int, producer: Int, creation: NSDate, amountOfProducedUnits: Int)
case Truck(wheels: Int, capacity: Int, weight: Int, length: Int, height: Int, width: Int, color: Int, name: Int, producer: Int, creation: NSDate, amountOfProducedUnits: Int)
case Motorbike(wheels: Int, capacity: Int, weight: Int, length: Int, height: Int, width: Int, color: Int, name: Int, producer: Int, creation: NSDate, amountOfProducedUnits: Int)
case Helicopter(wheels: Int, capacity: Int, weight: Int, length: Int, height: Int, width: Int, color: Int, name: Int, producer: Int, creation: NSDate, amountOfProducedUnits: Int)
case Train(wheels: Int, capacity: Int, weight: Int, length: Int, height: Int, width: Int, color: Int, name: Int, producer: Int, creation: NSDate, amountOfProducedUnits: Int)
// ...
}
나는 네가 내가 표현하고 싶은 뜻을 이해하고 싶다.
해결 방법
그래서...우리는 이런 상황을 어떻게 처리해야 합니까?흥미로운 것은 관련 유형의 초기화 구조기(initializer)와 클로즈업 사이에 미스터리한 유사성이 있다는 점이다.다음 코드를 보십시오.
enum Example {
case Test(x: Int)
}
let exampleClosure = Example.Test
코드 중
exampleClosure
의 유형은 무엇입니까?답은: (Int) -> Example
.네, 파라미터를 추가하지 않고 관련 형식을 가진 매거 구성원을 호출하면 패킷을 생성합니다. 정확한 형식의 파라미터를 사용하여 이 패킷을 호출하면 매거 구성원의 실례를 되돌려줍니다.이것은 다음 코드가 올바르고 정상적으로 작동할 수 있음을 나타낸다.
enum Fruit {
case Apple(amount: Int)
case Orange(amount: Int)
}
let appleMaker = Fruit.Apple
let firstApple = appleMaker(amount: 10)
let secondApple = appleMaker(amount: 12)
print(firstApple, secondApple)
// : Apple(10) Apple(12)
그래서 위의 엉망진창인 코드 중복 문제를 어떻게 간소화할 수 있을까?어디 보자.
import Foundation
enum Device {
case Phone(name: String, screenSize: CGSize)
case Watch(name: String, screenSize: CGSize)
case Tablet(name: String, screenSize: CGSize)
private static var initializers: [String: (name: String, screenSize: CGSize) -> Device] = {
return ["Phone": Device.Phone, "Watch": Device.Watch, "Tablet": Device.Tablet]
}()
static func fromDefaults(rawValue: String, name: String, screenSize: CGSize) -> Device? {
return Device.initializers[rawValue]?(name: name, screenSize: screenSize)
}
}
let iPhone = Device.fromDefaults("Phone", name: "iPhone SE", screenSize: CGSize(width: 640, height: 1134))
print(iPhone)
// :Optional(main.Device.Phone("iPhone SE", (640.0, 1134.0)))
이 코드가 무엇을 했는지 지적해 봅시다.우리는
Device
에 새로운 속성initializers
을 추가했다.이것은 유형이 [String: (name: String, screenSize: CGSize) -> Device]
인 사전Dictionary
이다.즉 String
유형의 키(key
)에서 우리Device
의 구성원 유형과 같은 클립을 비추는 것이다.간단하게 이전의 작은 기교를 이용하여 Phone: Device.Phone
라는 방식으로 클립을 되돌려주면 이 사전은 우리 모든 매거 구성원의 초기화 구조기를 포함한다.다음
fromDefaults
함수는 우리가 만들고 싶은 장치의 키 값만 알면 적합한 클립을 호출할 수 있습니다.이로 인해 코드가 많이 간소화되었다. 특히 더 큰 매거진 (위의 Vehicle의 예와 같다).보시다시피 현재 Device
실례를 만드는 것은 매우 간단합니다.Device.initializers["Phone"]?(name: "iPhone 5", screenSize: CGSize(width: 640, height: 1134))
원래 값을 그대로 사용하는 것처럼 열거에 Phone이라는 구성원이 없으면 빈 값을 되돌려줍니다.
물론 이 해결 방안은 완벽하지 않다. 우리는 여전히
initializers
라는 사전을 사용해야 한다. 그러나 모든 매거 구성원을 수동으로 일치시켜야 하는 것보다 이렇게 하면 대량의 중복 작업을 줄일 수 있다.마지막으로, 내가 더 이상 말하지 않아도 위의 코드가 조금 소홀히 되어 있다. 합격의 가장 좋은 실천은 간결하고 사람들로 하여금 손에 쥐고 있는 일에 전념하게 하는 것이다.그러나
Device.initializers["phone"]
처럼 문자열화된 방식은 가장 좋은 문법이 아니기 때문에 이 키들은 다른 곳에 합리적으로 정의되어야 한다.만약 네가 여기까지 읽었다면, 나는 네가 트위터에 나를 팬으로 찍어야 한다고 생각한다. (@terhechte)
이 문서는 SwiftGG 번역팀에서 번역하였으며, 작성자 번역 승인을 받았습니다. 최신 기사는http://swift.gg.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.