Как использовать общие параметры по умолчанию

Это мой код:

class Person {
    init<T: RawRepresentable>(raw: T = Child.johnDoe) {}
}

enum Child: String {
    case johnDoe
}

Это не компилируется. Ошибка:

Значение аргумента по умолчанию типа 'Child' не может быть преобразовано в тип 'T'

Почему это не может быть преобразовано? Согласно документам, Child.someEnum является RawRepresentable:

Перечисления с необработанными значениями Для любого перечисления со строковым, целочисленным или необработанным типом с плавающей точкой компилятор Swift автоматически добавляет соответствие RawRepresentable. При определении собственного настраиваемого перечисления вы задаете ему необработанный тип, указав необработанный тип в качестве первого элемента в списке наследования типов перечисления.

Это также компилирует:

class Person {
    static func accept<T: RawRepresentable>(raw: T) where T.RawValue == String {}
}

enum Child: String {
    case johnDoe
}

Person.accept(raw: Child.johnDoe)

Почему он не работает как параметр по умолчанию?

Случай использования: я хочу принять любой RawPresentable значение, чтобы я мог извлечь rawValue от него. Я хочу предоставить значение по умолчанию (всегда "") (я просто создаю структуру с rawValue = ""). Я не хочу создавать несколько инициализаторов, так как у меня есть несколько подклассов, и это может привести к путанице. Лучшее для меня - просто предоставить дефолт RawRepresentable объект.

Когда я добавляю приведение типа: init(ty: T = (Child.johnDoe как! T)), где T.RawValue == String {

}

Или сделай это

(ty: T? = nil)

Это компилируется. Но сейчас я не могу позвонить

let x = Person()

Это дает ошибку:

Общий параметр 'T' не может быть выведен

1 ответ

Решение

Это конечно возможно. Однако вы должны использовать свой собственный протокол и добавить значение по умолчанию для этого протокола:

protocol MyRawRepresentable: RawRepresentable {
    static var defaultValue: Self { get }
}

class Person {
    init<T: MyRawRepresentable>(raw: T = T.defaultValue) {}
}

enum Child: String, MyRawRepresentable {
    case johnDoe

    static let defaultValue: Child = .johnDoe
}

Есть и другая проблема. Как вы будете определять универсальный тип, если вы используете значение параметра по умолчанию, и все, что у вас будет, будет просто Person.init()?

Единственное решение, которое я вижу, - это также указать универсальный тип по умолчанию, что означает, что вы действительно хотите:

class Person {
   init<T: RawRepresentable>(raw: T) {
   }

   convenience init() {
       self.init(raw: Child.johnDoe)
   }
}

Если вы на самом деле не хотите сделать Person сам по себе универсальный класс, потому что тогда вы могли бы просто использовать

Person<Child>.init()
Другие вопросы по тегам