Распространение необязательного параметра через функцию (или инициализацию) в Swift

есть ли у кого-нибудь (лучший) способ сделать это?

Допустим, у меня есть дополнительный поплавок

let f: Float? = 2

Теперь я хочу преобразовать его в Double

let d = Double(f) //fail

Очевидно, это не удастся, но есть ли способ связать необязательное через функцию, как вы можете с вычисляемыми переменными? Сейчас я делаю вот что:

extension Float {
    var double: Double { return Double(self) }
}
let d: Double? = f?.double

Но мне очень не нравится ставить приведение в качестве вычисляемой переменной.

Другой вариант, который я рассмотрел, заключается в следующем:

public func optionalize<A,B>(_ λ : @escaping (A) -> B) -> (A?) -> B? {
    return { (a) in
        guard let a = a else { return nil }
        return λ(a)
    }
}
let d: Double? = optionalize(Double.init)(f)

Я понимаю, что могу сохранить значение «f», чтобы его развернуть. Однако во многих случаях необязательное значение будет параметром функции, возвращающей необязательный. Это приводит к промежуточным значениям в гвардии. Как видно из этого примера:

func foo(_ a: String?) throws -> Float {
    guard 
        let a = a,
        let intermediate = Float(a)
    else { throw.something }
    return intermediate
}

Здесь также возможно сбой преобразования String в Float. По крайней мере, с вычисляемой переменной эта функция foo немного чище

extension String {
    var float: Float? { return Float(self) }
}

func foo(_ a: String?) throws -> Float {
    guard 
        let a = a?.float
    else { throw.something }
    return a
}

Я не хочу переписывать необязательные версии частых инициалов.

Будем очень признательны за любые идеи. Спасибо!


person Mr Flynn    schedule 19.10.2016    source источник
comment
Сравните stackoverflow.com/questions/39425457/ .   -  person Martin R    schedule 20.10.2016
comment
Я рекомендую вам проверить Руны.   -  person user28434'mstep    schedule 20.10.2016


Ответы (1)


Вы можете просто использовать метод Optional map(_:), который вернет упакованное значение с данным преобразованием, примененным, если оно не равно нулю, иначе оно вернет nil.

let f : Float? = 2

// If f is non-nil, return the result from the wrapped value passed to Double(_:),
// else return nil.
let d = f.map { Double($0) }

Что, как вы указываете в комментариях ниже, также можно сказать так:

let d = f.map(Double.init)

Это связано с тем, что map(_:) в этом случае ожидает функцию преобразования типа (Float) -> Double, а значение с плавающей точкой Double инициализатор является такой функцией.

Если преобразование также возвращает необязательный параметр (например, при преобразовании String в Int), вы можете использовать _ 11_, который просто передает результат nil преобразования обратно вызывающему:

let s : String? = "3"

// If s is non-nil, return the result from the wrapped value being passed to the Int(_:)
// initialiser. If s is nil, or Int($0) returns nil, return nil.
let i = s.flatMap { Int($0) }
person Hamish    schedule 19.10.2016
comment
Спасибо! Не знаю, почему я об этом не подумал! Только изменение было бы f.map (Double.init) просто как стилистическая вещь;) - person Mr Flynn; 20.10.2016
comment
@MrFlynn Конечно, спасибо, что упомянули об этом - я отредактировал свой ответ, чтобы включить его. Хотя обратите внимание, что иногда компилятор хочет, чтобы вы устраняли неоднозначность инициализатора, говоря map(XYZ.init(_:)) - и в этот момент я определенно думаю, что синтаксис закрытия более чистый :) - person Hamish; 20.10.2016