如何使函数在可选值序列上运行?

时间:2014-11-27 20:21:04

标签: swift

如何指定函数应该对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
}

2 个答案:

答案 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)

序列元素需要两个操作:

  1. 检查元素是否为nil
  2. 如果找不到任何内容,请创建相应类型的nil值作为默认返回值。
  3. 对于#2,我们可以使用enum Optional符合NilLiteralConvertible的事实 协议。对于#1,我已经定义了一个NilComparable协议 enum Optional符合它:

    protocol NilComparable {
        func isNil() -> Bool
    }
    extension Optional : NilComparable {
        func isNil() -> Bool { return self == nil }
    }
    

    现在我们可以为元素符合的所有序列定义一个函数 到NilComparableNilLiteralConvertible。所有选项序列 属于这一类:

    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? {
        // ...
    }
    

    但这实际上导致编译器崩溃。我不知道这个是否编译。