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

8

我想实现一个自定义可迭代类,它可以包含空元素,类似于[Any?]。符合SequenceType的大部分规则,但是GeneratorType.next()的约定是当所有元素都被耗尽时应返回nil。这有解决方法吗?


2个回答

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博客中有关nilOptional(nil)之间差异及其应用的文章"Optionals Case Study: valuesForKeys"


更新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)
}

0

我们可以创建符合SequenceType协议的对象,这些对象返回Optionals。然而,因为容易出错,所以在实现您的next()方法(使用自定义GeneratorType协议符合的对象)或者实现您的anyGenerator(_:)闭包参数(使用AnyGenerator)时,必须非常小心。

一般来说,您应该遵循以下模式:

如果您使用一个符合自定义GeneratorType协议的对象,并希望它返回Int?,则必须将next()方法的返回类型设置为Int??
同样地,如果您使用一个AnyGenerator实例并希望它返回Int?AnyGenerator<Int?>),则必须向您的anyGenerator方法传递一个闭包,其类型为() -> Int??

使用自定义生成器

下面的 Playground 代码受 @Martin R 的回答启发,展示了如何实现一个符合 SequenceType 协议的 Struct,并使用一个符合 GeneratorType 协议的自定义结构返回 Optional

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.None替换return i % 2 == 0 ? i : Optional<Int>.None,则您的for循环将不会打印任何内容,您的数组也将为空。
另外请注意,如果您在先前的代码中用return Int?.None替换return Int??.None,则会生成一个无限循环的nil

使用AnyGenerator

以下Playground代码展示了如何以非常谨慎的方式实现符合SequenceType协议的Struct,并使用返回Optional元素的AnyGenerator实例:

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)]

前面的序列可以用更简洁但有点不太安全的方式重写:

struct OddSequence: SequenceType {
    
    func generate() -> AnyGenerator<Int?> {
        var i = 0
        let generator: AnyGenerator<Int?> = anyGenerator {
            if i >= 4 { return nil }
            i += 1
            return i % 2 != 0 ? Optional(nil) : i
        }
        
        return generator
    }
    
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接