是否可以实现包含nil元素的Swift SequenceType?

时间:2014-09-11 18:42:18

标签: swift

我想实现一个可以包含nil元素的自定义可迭代类,类似于[Any?]。符合SequenceType大部分都有效,除了GeneratorType.next()的契约表示当所有元素都已用完时它应该返回nil。有解决方法吗?

2 个答案:

答案 0 :(得分:13)

这是一个(非常愚蠢)的例子:

struct OddSequence : SequenceType {

    func generate() -> GeneratorOf<Int?> {
        var current = 0
        return GeneratorOf<Int?>() {
            if current >= 6 {
                return nil
            }
            current++
            if current % 2 == 0 {
                return current
            } else {
                return Optional(nil)
            }
        }
    }
}


for x in OddSequence() {
    println(x)
}

输出:

nil
Optional(2)
nil
Optional(4)
nil
Optional(6)

生成器为每个元素返回一个可选项(可以是Optional(nil)), 如果序列用尽,则nil

另请参阅Swift博客中的"Optionals Case Study: valuesForKeys",了解nil和之间的区别 Optional(nil)及其应用程序。


Swift 2的更新:

struct OddSequence : SequenceType {

    func generate() -> AnyGenerator<Int?> {
        var current = 0
        return anyGenerator {
            if current >= 6 {
                return nil
            }
            current++
            if current % 2 == 0 {
                return current
            } else {
                return Optional(nil)
            }
        }
    }
}

for x in OddSequence() {
    print(x)
}

答案 1 :(得分:0)

可以创建返回SequenceType s的Optional协议符合对象。但是,因为它很容易出错,所以在实现next()方法(使用自定义GeneratorType协议符合对象)或实现anyGenerator(_:)闭包参数时必须非常谨慎(使用AnyGenerator)。

根据经验,您应该始终遵循以下模式:

  

如果您使用自定义GeneratorType协议符合对象并希望它返回Int?,则必须将next()方法的返回类型设置为Int??

     

以同样的方式,如果您使用AnyGenerator实例并希望它返回Int?AnyGenerator<Int?>),则必须传递() -> Int??类型的闭包到anyGenerator方法。

使用自定义生成器

以下Playground代码受@Martin R的回答启发,展示了如何实现符合SequenceType Struct协议的GeneratorType协议与自定义Optional协议一致的结构返回{ {1}} S:

struct OddGenerator: GeneratorType {
    var i = 0

    mutating func next() -> Int?? {
        if i >= 4 {
            return Int??.None
            //return Optional.None // also works
            //return nil // also works
        }
        i += 1
        return i % 2 == 0 ? i : Optional<Int>.None
        //return i % 2 == 0 ? Optional.Some(i) : Int?.None // also works
        //return i % 2 == 0 ? .Some(i) : .Some(Optional<Int>.None) // also works
        //return i % 2 == 0 ? Optional(i) : Optional(nil) // also works
    }
}

struct OddSequence: SequenceType {
    func generate() -> OddGenerator {
        return OddGenerator()
    }
}

for x in OddSequence() {
    print(x)
}

/*
prints:
nil
Optional(2)
nil
Optional(4)
*/

let array = Array(OddSequence())
print(array) // prints: [nil, Optional(2), nil, Optional(4)]

请注意,如果您使用return i % 2 == 0 ? i : Optional<Int>.None替换上一代码中的return i % 2 == 0 ? i : Optional.None,则for循环将不会打印任何内容,并且您的数组将为空。

另请注意,如果您使用return Int??.None替换上一代码中的return Int?.None,则会生成nil的无限循环。

使用AnyGenerator

以下Playground代码显示了如何以非常谨慎的方式实现符合SequenceType的{​​{1}}协议与返回Struct元素的AnyGenerator实例:

Optional

以前的序列可以用非常简洁但安全性较低的方式重写:

struct OddSequence: SequenceType {

    func generate() -> AnyGenerator<Optional<Int>> {
        var i = 0
        let generator: AnyGenerator<Optional<Int>> = anyGenerator {
            () -> Optional<Optional<Int>> in

            if i >= 4 { return Optional<Optional<Int>>.None }
            i += 1
            return i % 2 != 0 ?
                Optional<Optional<Int>>.Some(Optional<Int>.None) :
                Optional<Optional<Int>>.Some(Optional<Int>.Some(i))
        }

        return generator
    }

}

for x in OddSequence() {
    print(x)
}

/*
prints:
nil
Optional(2)
nil
Optional(4)
*/

let array = Array(OddSequence())
print(array) // prints: [nil, Optional(2), nil, Optional(4)]