Я попытался довести эту проблему до ее простейшей формы следующим образом.
Настройка
Xcode Version 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")
}
}
Error
Xcode дает мне следующую ошибку при попытке инициализировать MyEnum
своим инициализатором исходного значения:
Cannot convert the expression type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Примечания
-
В Руководство по быстрому языку:
Если вы определяете перечисление с типом raw-value, перечисление автоматически получает инициализатор, который принимает значение типа необработанных значений (в качестве параметра с именем
rawValue
) и возвращает либо элемент перечисления, либоnil
. -
Пользовательский инициализатор для
MyEnum
был определен в расширении для проверки того, был ли инициализатор исходного значения перечисления удален из-за следующего случая из Руководство по языку. Однако он достигает того же результата ошибки.Обратите внимание, что если вы определяете пользовательский инициализатор для типа значения, у вас больше не будет доступа к инициализатору по умолчанию (или инициализатору по умолчанию, если это структура) для этого типа. [...]
Если вы хотите, чтобы ваш настраиваемый тип значения был инициализирован инициализатором по умолчанию и инициализатором по порядку, а также с вашими собственными инициализаторами, напишите свои пользовательские инициализаторы в расширении, а не как часть исходной реализации типов значений. -
Перемещение определения перечисления на
MyClass.swift
устраняет ошибку дляbar
, но не дляfoo
. -
Удаление пользовательского инициализатора устраняет обе ошибки.
-
Одним из способов решения проблемы является включение следующей функции в определение перечисления и использование ее вместо предоставленного инициализатора исходных значений. Таким образом, кажется, что добавление пользовательского инициализатора имеет аналогичный эффект для маркировки инициализатора исходного значения
private
.init?(raw: Int) { self.init(rawValue: raw) }
-
Явное объявление соответствия протокола
RawRepresentable
вMyClass.swift
разрешает встроенную ошибку дляbar
, но приводит к ошибке компоновщика о повторяющихся символах (поскольку перечисления типа raw-value неявно соответствуютRawRepresentable
).extension MyEnum: RawRepresentable {}
Может ли кто-нибудь дать немного больше информации о том, что происходит здесь? Почему исходный инициализатор не доступен?