Дополнительное расширение для любых типов

Я хочу написать расширение Optional для любых типов.

Мой код для целого числа:

extension Optional where Wrapped == Int {

    func ifNil<T>(default: T) -> T {
        if self != nil {
            return self as! T
        }
        return value
    }
}

var tempInt: Int?

tempInt.ifNil(default: 2) // returns 2

tempInt = 5

tempInt.ifNil(default: 2) // returns 5

Он работает, но это Optional(Int) расширение (Optional where Wrapped == Int), я хочу использовать это расширение для любых типов, таких как Date, String, Double и т. Д.

Ваши предложения?


person emrcftci    schedule 27.07.2019    source источник
comment
isNil(value: 2) действительно похоже, что он должен проверять, является ли 2 nil, и возвращать Bool. Лучшее название метода должно включать такие термины, как or, default, else, например unwrapped(orDefault: 2)   -  person Alexander    schedule 27.07.2019


Ответы (2)


Ответ на ваш основной вопрос - просто удалить предложение where:

extension Optional { 
    // ... the rest is the same 
    func isNil<T>(value: T) -> T {
        if self != nil {
            return self as! T
        }
        return value
    }
}

Теперь это применимо ко всем опциям.

Но этот код совершенно не работает. Вылетает, если T не совпадает с Wrapped. Таким образом, вы действительно имели бы в виду неуниверсальную функцию, которая работает на Wrapped:

extension Optional {
    func isNil(value: Wrapped) -> Wrapped {
        if self != nil {
            return self!  // `as!` is unnecessary
        }
        return value
    }
}

Но это просто изощренный способ сказать ?? (как указывает Мэтт)

extension Optional {
    func isNil(value: Wrapped) -> Wrapped { self ?? value }
}

За исключением того, что ?? намного мощнее. Он включает автоматическое закрытие, которое позволяет избежать оценки значения по умолчанию, если оно не используется на самом деле, и которое может throw. Кроме того, в большинстве случаев это гораздо более идиоматичный Swift. Вы можете найти person Rob Napier    schedule 27.07.2019


Необязательный является уже универсальным. Он уже принимает любой тип в качестве параметризованного типа. Его параметризация уже имеет имя: Wrapped. Просто скажите Wrapped вместо T. Ваш T Wrapped.

extension Optional {
    func isNil<Wrapped>(value: Wrapped) -> Wrapped {
        if self != nil {
            return self as! Wrapped
        }
        return value
    }
}

Если по какой-то причине вы действительно предпочитаете T, используйте псевдоним типа. Это всего лишь имя:

extension Optional {
    typealias T = Wrapped
    func isNil<T>(value: T) -> T {
        if self != nil {
            return self as! T
        }
        return value
    }
}

Но в любом случае ваше расширение совершенно не нужно, потому что это то, что уже делает оператор nil-coalescing ??.

var tempInt: Int?
tempInt ?? 2 /// returns 2
tempInt = 5
tempInt ?? 2 /// returns 5
person matt    schedule 27.07.2019
comment
Есть важное (но подозреваю, что случайное) отличие. Поскольку <Wrapped> передается в качестве универсального параметра функции, isNil(value: "") выйдет из строя, если tempInt не равно нулю. Я думаю, это должно быть isNil(...), а не isNil<Wrapped>(...) - person Rob Napier; 27.07.2019
comment
И, конечно, нужно реализовать func isNil(value: Wrapped) -> Wrapped { self ?? value } (как вы говорите: D) - person Rob Napier; 27.07.2019
comment
Да, я понимаю, что вы имеете в виду по поводу первой части. Но эта ошибка встроена в исходный код OP; моей целью было не улучшить код, а просто ответить на вопрос, который заключался в том, как преобразовать исходный код во что-то, что применимо независимо от параметризованного типа. Все расширение написано плохо и неразумно, в этом нет никаких сомнений. - person matt; 27.07.2019
comment
Честно, хотя тогда я бы только предоставил <T> версию. Версия <Wrapped> может ввести людей в заблуждение, поскольку она затеняет связанный тип, который, как я подозреваю, многие читатели не поймут. (Сказать, что ваш T равен Wrapped, очень похоже на T == Optional.Wrapped, что неверно.) Даже во второй версии T не равно Optional.T. Универсальный параметр скрывает псевдонимы. - person Rob Napier; 27.07.2019