通过Swift中的函数(或Init)传播可选内容 [英] Propagate an optional through a function (or Init) in Swift
问题描述
有人有(更好)的方法吗?
does anyone have a (better) way to do this?
假设我有一个可选的Float
Lets say I have a optional Float
let f: Float? = 2
现在我想将其转换为Double
Now I want to cast it to a Double
let d = Double(f) //fail
这显然会失败,但是有没有办法像通过计算变量那样通过函数链接可选项?我现在正在做的是这样:
This will obviously fail but is there a way to chain the optional through the function like you can with calculated variables? What I am doing now is this:
extension Float {
var double: Double { return Double(self) }
}
let d: Double? = f?.double
但是我真的不喜欢将强制转换作为计算变量.
But I really do not like putting a cast as a calculated variable.
我考虑使用的另一个选项是:
Another option I have considered using is this:
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'的值来解开它.但是,在许多情况下,可选值将是返回可选值的函数的参数.这导致防护中的中间值.如本例所示:
I realize I can guard the value of 'f' to unwrap it. However in many cases the optional value will be the parameter for a function that returns an optional. This leads to intermediate values in the guard. As seen in this example:
func foo(_ a: String?) throws -> Float {
guard
let a = a,
let intermediate = Float(a)
else { throw.something }
return intermediate
}
在这里,从String到Float的转换也可能会失败. 至少使用计算出的变量,该foo函数会更干净
Here it is possible for the cast from String to Float to fail also. At least with a calculated variable this foo function is a bit cleaner
extension String {
var float: Float? { return Float(self) }
}
func foo(_ a: String?) throws -> Float {
guard
let a = a?.float
else { throw.something }
return a
}
我不想重写频繁初始化的可选版本.
I do not want to rewrite optional versions of frequent inits.
任何想法都将不胜感激.谢谢!
Any ideas will be much appreciated. Thanks!
推荐答案
You can simply use Optional
's map(_:)
method, which will return the wrapped value with a given transform applied if it's non-nil, else it will return 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) }
正如您在下面的评论中指出的那样,也可以这样表示:
Which, as you point out in the comments below, can also be said as:
let d = f.map(Double.init)
这是因为在这种情况下,map(_:)
需要类型为(Float) -> Double
的转换函数,并且
This is because map(_:)
expects a transformation function of type (Float) -> Double
in this case, and Double
's float initialiser is such a function.
如果转换还返回了可选内容(例如,将String
转换为Int
时),则可以使用
If the transform also returns an optional (such as when converting an String
to a Int
), you can use flatMap(_:)
, which simply propagates a nil
transform result back to the caller:
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) }
这篇关于通过Swift中的函数(或Init)传播可选内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!