การเอาชนะ Enum init? (rawValue: String) เพื่อไม่ให้เป็นทางเลือก

ฉันต้องการให้ init จาก rawValue สำหรับ enum ของฉันใน Swift เพื่อส่งคืนค่าเริ่มต้นหาก rawValue init จะส่งคืนศูนย์ ตอนนี้ฉันมีบางอย่างเช่นนี้:

public init(fromRawValue: String){
        self = Language(rawValue: fromRawValue) ?? .English
}

ฉันไม่ชอบสิ่งนี้เพราะมันเป็นตัวเริ่มต้นใหม่ทั้งหมด ฉันพยายามทำอะไรแบบนี้:

public init(rawValue: String){
        self = Language(rawValue: fromRawValue) ?? .English
}

แต่ฉันมีข้อยกเว้นรันไทม์กับการเข้าถึงที่ไม่ดี ฉันสามารถทำให้มันใช้งานได้หรือฉันแค่ต้องใช้อันใหม่นี้และฉันไม่สามารถแทนที่อันเดิมเพื่อให้เป็นทางเลือกได้

ฉันต้องการทราบว่าเป็นไปได้หรือไม่ที่จะแทนที่ init ดั้งเดิมจาก rawValue ไม่ใช่วิธีแก้ปัญหาด้วยอันใหม่ทั้งหมดที่ใช้อันที่ล้มเหลว


person Prettygeek    schedule 31.01.2016    source แหล่งที่มา
comment
อาจซ้ำกันของ Nonfailable enum Initializer พร้อมค่าเริ่มต้น   -  person Kevin    schedule 01.02.2016


คำตอบ (2)


ตัวเริ่มต้นเริ่มต้นคือ failable หมายความว่าหากพารามิเตอร์ที่ได้รับไม่ตรงกับตัวพิมพ์แจงนับที่ถูกต้อง จะส่งคืนค่า nil

ตอนนี้คุณต้องการทำ 2 สิ่งที่เข้ากันไม่ได้:

  1. คุณต้องการ กำหนดใหม่ ตัวเริ่มต้นทำให้ไม่ล้มเหลว ที่จริงแล้วคุณต้องการให้ค่าแจงนับเริ่มต้นสร้างขึ้นเมื่อพารามิเตอร์ที่ได้รับไม่ถูกต้อง
  2. ภายในตัวเริ่มต้นที่กำหนดไว้ใหม่ของคุณ คุณต้องการเรียกตัวเริ่มต้นที่ล้มเหลว (ซึ่งไม่มีอยู่แล้ว) โดยใช้ชื่อเดียวกันกับตัวใหม่

สิ่งนี้เป็นไปไม่ได้ ฉันมีวิธีแก้ไขที่เป็นไปได้ 3 วิธีดังต่อไปนี้:

1) การสร้าง init อื่น

คุณกำหนดตัวเริ่มต้นที่ไม่สามารถล้มเหลวใหม่ด้วยค่าเริ่มต้น ชื่อพารามิเตอร์อื่น และภายในนั้นคุณเรียกตัวเริ่มต้นที่ล้มเหลวเริ่มต้น

enum Language: String {

    case english = "English", italian = "Italian", french = "French"

    init(fromRawValue: String){
        self = Language(rawValue: fromRawValue) ?? .english
    }
}

2) กำหนดค่าเริ่มต้นใหม่

คุณกำหนดตัวเริ่มต้นใหม่ คุณทำให้มันไม่ล้มเหลว และคุณเขียนตรรกะทั้งหมดไว้ข้างใน

enum Language: String {

    case english = "English", italian = "Italian", french = "French"

    init(rawValue: String) {
        switch rawValue {
        case "Italian": self = .italian
        case "French": self = .french
        default: self = .english
        }
    }
}

3) การสร้างฟังก์ชันแบบคงที่

enum Language: String {

    case english = "English", italian = "Italian", french = "French"

    static func build(rawValue: String) -> Language {
        return Language(rawValue: rawValue) ?? .english
    }
}

ตอนนี้คุณสามารถสร้างการเขียนค่า Language ได้:

let italian = Language.build(rawValue: "Italian") // Italian
let defaultValue = Language.build(rawValue: "Wrong input") // English
person Luca Angeletti    schedule 01.02.2016
comment
คำตอบที่ยอดเยี่ยม ตัวตน = ... เป็นสิ่งล้ำค่า นักเก็ต Swift ที่ซ่อนอยู่ทุกประเภทใน lang นี้ :) - person Marchy; 23.03.2017
comment
คุณสามารถแทนที่ Language ในเครื่องมือเริ่มต้นของแนวทาง #1 เป็น type(of: self).init สำหรับแนวทางทั่วไปมากขึ้น - person shim; 30.08.2018

เมื่อเพิ่มโซลูชันของ Luca เพื่อกำหนดค่าเริ่มต้นใหม่แล้ว ยังเป็นไปได้ที่จะทำให้ประเภทพารามิเตอร์ rawValue เป็นตัวเลือกเพิ่มเติม ซึ่งจะลดโค้ดบางส่วนที่ไซต์การโทรเมื่อแหล่งข้อมูลไม่น่าเชื่อถือ

enum PrecipitationType: String {
    case rain, snow, sleet, none

    typealias RawValue = String

    init(rawValue: String?) {
        guard let rawValue = rawValue else { self = .none; return }

        switch rawValue {
            case PrecipitationType.rain.rawValue: self = .rain
            case PrecipitationType.snow.rawValue: self = .snow
            case PrecipitationType.sleet.rawValue: self = .sleet
            default: self = .none
        }
    }
}

เมื่อฉันลองสิ่งนี้ครั้งแรก มันสร้างข้อผิดพลาดหลายอย่าง กุญแจสำคัญคือการกำหนด RawValue typealias ใหม่เพื่อรักษาความสอดคล้องกับ RawRepresentable

person Nathan Hosselton    schedule 05.08.2017