1

コレクションに基づいてランダムジェネレーターを提供するクラスがあります。
これはランダム ジェネレーターであるため (コレクションが空でない限り、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'
  }
}
4

1 に答える 1

3

使用できます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))
}

GeneratorOfnext()関数を表すクロージャから直接作成することもできます。

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定義されているラッパーのわずかな変更を定義できます 。:

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()
    }
}

GeneratorOf次に、次のように置き換えGeneratorOnlyOfます。

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

または、(コメントで既に示したように) 独自の 非ジェネリックプロトコルを定義することもできます。

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

内部ジェネレーターをそのプロトコルに準拠させます。

internal struct myGenerator : MyProtocolGenerator { ... }

generate()メソッドからそれを返します。

public class myClass {

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

(古い回答:)generate()メソッドは、プロトコルではなく、具体的なジェネレータの型を返します:

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>
    // ...
}
于 2015-03-29T20:06:45.023 に答える