Я намагався звести це питання до найпростішої форми з наступним.
Налаштування
Версія Xcode 6.1.1 (6A2008a)
Перелік, визначений у MyEnum.swift
:
internal enum MyEnum: Int {
case Zero = 0, One, Two
}
extension MyEnum {
init?(string: String) {
switch string.lowercaseString {
case "zero": self = .Zero
case "one": self = .One
case "two": self = .Two
default: return nil
}
}
}
і код, який ініціалізує перерахування в іншому файлі MyClass.swift
:
internal class MyClass {
let foo = MyEnum(rawValue: 0) // Error
let fooStr = MyEnum(string: "zero")
func testFunc() {
let bar = MyEnum(rawValue: 1) // Error
let barStr = MyEnum(string: "one")
}
}
Помилка
Xcode видає мені таку помилку при спробі ініціалізації за MyEnum
допомогою ініціалізатора вихідного значення:
Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Примітки
Відповідно до мовного посібника Swift :
Якщо ви визначаєте перерахування з типом необробленого значення, перерахування автоматично отримує ініціалізатор, який приймає значення типу вихідного значення (як параметр, що викликається
rawValue
) і повертає або елемент перерахування, абоnil
.Спеціальний ініціалізатор для
MyEnum
був визначений у розширенні, щоб перевірити, чи було видалено ініціалізатор необроблених значень перелічення через наступний випадок з Мовного довідника . Однак він досягає того самого результату помилки.Зверніть увагу, що якщо ви визначите спеціальний ініціалізатор для типу значення, у вас більше не буде доступу до ініціалізатора за замовчуванням (або ініціалізатора, що входить до складу, якщо це структура) для цього типу. [...]
Якщо ви хочете, щоб ваш власний тип значення можна було ініціалізувати за допомогою типового ініціалізатора та ініціалізатора по всьому члену, а також за допомогою власних користувацьких ініціалізаторів, напишіть власні ініціалізатори у розширенні, а не як частина оригінальної реалізації типу значення.Переміщення визначення перерахування
MyClass.swift
усуває помилку для,bar
але не дляfoo
.Видалення спеціального ініціалізатора усуває обидві помилки.
Одним з обхідних шляхів є включення наступної функції до визначення переліку та використання її замість наданого ініціалізатора вихідних значень. Отже, здається, ніби додавання власного ініціалізатора має подібний ефект до позначення ініціалізатора необробленого значення
private
.init?(raw: Int) { self.init(rawValue: raw) }
Явне оголошення про відповідність протоколу
RawRepresentable
inMyClass.swift
усуває вбудовану помилкуbar
, але призводить до помилки компонувальника щодо повторюваних символів (оскільки перелічені типи необроблених значень неявно відповідаютьRawRepresentable
).extension MyEnum: RawRepresentable {}
Хтось може дати трохи більше розуміння того, що тут відбувається? Чому не доступний ініціалізатор необробленого значення?
internal
область (або принаймні відповідати типу), а неprivate
.