Skip to main content
 首页 » 操作系统

swift之返回自定义 GeneratorType

2024年01月01日58三少

我有一个类,它应该提供一个基于集合的随机生成器。
因为它是一个随机生成器(next() 永远不会返回 nil,除非集合为空),我不希望能够将此生成器用作 sequenceType(不支持 'for in' 以避免无限循环)

我似乎无法获得正确的方法签名。

这是我构建的框架,我已经包含了 3 次尝试及其相应的编译器错误。

public protocol myProtocol { 
  var name : String { get } 
} 
 
internal struct myProtocolStruct: myProtocol { 
  let name : String 
  init(name: String) { 
    self.name = name 
  } 
} 
 
internal struct myGenerator : GeneratorType { 
  let names : [myProtocol] 
 
  init(names: [myProtocol]) { 
    self.names = names 
  } 
 
  mutating func next() -> myProtocol? { 
    return names.first 
  } 
} 
 
public class myClass { 
 
  private var items : [myProtocol] 
  public init() { 
    let names = ["0", "1", "2"] 
    items = names.map{ myProtocolStruct(name: $0) } 
  } 
 
  public func generate0() -> GeneratorType { //  error: protocol 'GeneratorType' can only be used as a generic constraint because it has Self or associated type requirements 
    let x = myGenerator(names: items) 
    return x 
  } 
  public func generate1<C: GeneratorType where C.Element == myProtocol>() -> C { 
    let x = myGenerator(names: items) 
    return x    //  error: 'myGenerator' is not convertible to 'C' 
  } 
  public func generate2<C: GeneratorType where C.Element: myProtocol>() -> C { 
    let x = myGenerator(names: items) 
    return x    //  error: 'myGenerator' is not convertible to 'C' 
  } 
} 

请您参考如下方法:

您可以使用 GeneratorOf:

/// A type-erased generator. 
/// 
/// The generator for `SequenceOf<T>`.  Forwards operations to an 
/// arbitrary underlying generator with the same `Element` type, 
/// hiding the specifics of the underlying generator type. 
/// 
/// See also: `SequenceOf<T>`. 
struct GeneratorOf<T> : GeneratorType, SequenceType { ... } 

GeneratorOf 可以从另一个生成器创建(需要 不公开):

public func generate() -> GeneratorOf<myProtocol> { 
    return GeneratorOf(myGenerator(names: items)) 
} 

GeneratorOf 也可以直接从表示 next() 函数的闭包中创建:

public func generate() -> GeneratorOf<myProtocol> { 
    var genItems = self.items // capture the items for use in the closure 
    return GeneratorOf { 
        // Return next element, this is just an example which 
        // returns and removes the first element from the array: 
        return genItems.count > 0 ? genItems.removeAtIndex(0) : nil 
    } 
} 

如果你想返回一个不符合 SequenceType 那么您可以对定义在 How is a type-erased generic wrapper implemented? :

public struct GeneratorOnlyOf<T> : GeneratorType { 
 
    private let _next:() -> T? 
 
    init(_ nextElement: () -> T?) { 
        _next = nextElement 
    } 
 
    init<G : GeneratorType where G.Element == T>(var _ base: G) { 
        _next = { base.next() } 
    } 
 
    public mutating func next() -> T? { 
        return _next() 
    } 
} 

然后用GeneratorOnlyOf替换GeneratorOf:

public func generate() -> GeneratorOnlyOf<myProtocol> { 
    return GeneratorOnlyOf(myGenerator(names: items)) 
} 

或者你可以(正如你已经在评论中指出的那样)定义你自己的 非通用协议(protocol):

public protocol MyProtocolGenerator { 
    mutating func next() -> myProtocol? 
} 

让你的内部生成器符合该协议(protocol):

internal struct myGenerator : MyProtocolGenerator { ... } 

然后从 generate() 方法返回:

public class myClass { 
 
    // ... 
    public func generate() -> MyProtocolGenerator { 
        return myGenerator(names: items) 
    } 
} 

(旧答案:) generate() 方法返回具体的生成器类型,而不是 协议(protocol):

func generate() -> myGenerator { 
    let x = myGenerator(names: items) 
    return x 
} 

比较内置Swift类型的生成器,例如

struct Array<T> : MutableCollectionType, Sliceable { 
    // ... 
    func generate() -> IndexingGenerator<[T]> 
    // ... 
} 

或

struct Dictionary<Key : Hashable, Value> : CollectionType, DictionaryLiteralConvertible { 
    // ... 
    func generate() -> DictionaryGenerator<Key, Value> 
    // ... 
}