如何指定函数应该对Swift中的一系列可选值进行操作?例如,我想创建一个这样的函数,它适用于序列的Array of Optional值。
// Given an array of optional values, return the first one with a value, if any
func firstValue<E>(ary: [E?]) -> E? {
for e in ary {
if let x = e {
return x
}
}
return nil
}
我希望能起作用,但不会,因为没有OptionalType
这样的东西:
func firstValue<C: SequenceType where C.Generator.Element: OptionalType>(seq: C) -> C.Generator.Element {
var g = seq.generate()
while let e = g.next() {
return e
}
return nil
}
答案 0 :(得分:2)
试试这个:
func firstValue<E, S: SequenceType where S.Generator.Element == Optional<E> >(seq: S) -> E? {
var g = seq.generate()
while let e:Optional<E> = g.next() {
if e != nil {
return e
}
}
return nil
}
let a:[Int?] = [nil,nil, 42, nil]
println(firstValue(a)) // -> 42 as Int?
我使用Xcode版本6.1.1(6A2006)和版本6.2(6C86e)进行了测试
注意
在:Optional<E>
条件下没有while
,编译器崩溃。
如果我们声明这样的函数,编译器会在某些环境中发生冲突。
func firstValue<S: SequenceType, E where S.Generator.Element == Optional<E> > {
// ^^^^^^^^^^^^^^^^^^ replaced E and S
我认为这些是编译器错误。请参阅以下评论。
答案 1 :(得分:1)
序列元素需要两个操作:
nil
和nil
值作为默认返回值。对于#2,我们可以使用enum Optional
符合NilLiteralConvertible
的事实
协议。对于#1,我已经定义了一个NilComparable
协议
enum Optional
符合它:
protocol NilComparable {
func isNil() -> Bool
}
extension Optional : NilComparable {
func isNil() -> Bool { return self == nil }
}
现在我们可以为元素符合的所有序列定义一个函数
到NilComparable
和NilLiteralConvertible
。所有选项序列
属于这一类:
func firstValue<C: SequenceType where
C.Generator.Element : NilComparable,
C.Generator.Element : NilLiteralConvertible
>(seq: C) -> C.Generator.Element {
var gen = seq.generate()
while let elem = gen.next() {
if !elem.isNil() {
return elem
}
}
return nil // Here NilLiteralConvertible is used.
}
示例:
let arr = [nil, nil, Optional(1), Optional(2)] // Type is [Optional<Int>]
println(firstValue(arr)) // Output: Optional(1)
更新:已有功能
func !=<T>(lhs: T?, rhs: _OptionalNilComparisonType) -> Bool
将任何可选值与nil
进行比较,因此可以简化上述协议
到
protocol NilComparable {
func !=(lhs: Self, rhs: _OptionalNilComparisonType) -> Bool
}
extension Optional : NilComparable { } // Already conforming
然后我们可以写if elem != nil { ... }
代替if !elem.isNil() { ... }
在功能中。
可能的缺点是_OptionalNilComparisonType
不正式
记录。
备注:我试图将该函数声明为
func firstValue<C: SequenceType, E where C.Generator.Element == Optional<E> >(seq: C) -> E? {
// ...
}
但这实际上导致编译器崩溃。我不知道这个是否编译。