swift - 返回泛型集合的迭代器 - Swift 4.2

标签 swift generics collections iterator

我可以按如下方式编写迭代器:

enum Stage { case a, ab, end }

struct SetMaker<Input: Hashable>: Sequence, IteratorProtocol {
  var a,b: Input
  var stage = Stage.a

  init(a: Input, b: Input) {
    self.a = a
    self.b = b
  }

  mutating func next() -> Set<Input>? {
    switch stage {
    case .a:    stage = .ab;   return Set<Input>([a])
    case .ab:   stage = .end;  return Set<Input>([a,b])
    case .end:                 return nil
    }
  }
}

let setMaker = SetMaker(a: "A", b: "B")
for x in setMaker {
  print(x)
}

struct ArrayMaker<Input: Hashable>: Sequence, IteratorProtocol {
  var a: Input
  var b: Input
  var stage = Stage.a

  init(a: Input, b: Input) {
    self.a = a
    self.b = b
  }

  mutating func next() -> Array<Input>? {
    switch stage {
    case .a:    stage = .ab;   return Array<Input>([a])
    case .ab:   stage = .end;  return Array<Input>([a,b])
    case .end:                 return nil
    }
  }
}

let arrayMaker = ArrayMaker(a: "A", b: "B")
for x in arrayMaker {
  print(x)
}

第一个返回集合序列,第二个返回数组序列。

这些都工作得很好,但我喜欢让我的代码保持“DRY”(即不要重复自己)。

所以我想写一些通用的东西来允许构建其中任何一个。 我的尝试是:

struct AnyMaker<Input: Hashable, CollectionType>: Sequence, IteratorProtocol {
  var a,b: Input
  var stage = Stage.a

  init(a: Input, b: Input) {
    self.a = a
    self.b = b
  }

  mutating func next() -> CollectionType<Input>? {
    switch stage {
    case .a:    stage = .ab;   return CollectionType<Input>([a])
    case .ab:   stage = .end;  return CollectionType<Input>([a,b])
    case .end:                 return nil
    }
  }
}

但这不能编译。 任何帮助表示赞赏:-)

编辑...

@Rob 提出了一个很好的建议,这让我能够部分实现 - 请参阅他的答案。 但如果我有时希望 Collection 成为一个 Set,那么就会出现问题,因为 Set 不是 RangeReplaceable。

换句话说,我创建了一段略有不同的代码:

struct Pairs<C>: Sequence, IteratorProtocol
where C: RangeReplaceableCollection {

  var collection: C
  var index: C.Index

  init(_ collection: C) {
    self.collection = collection
    index = self.collection.startIndex
  }

  mutating func next() -> C? {
    guard index < collection.endIndex else { return nil }
    let element1 = collection[index]
    index = collection.index(after: index)
    guard index < collection.endIndex else { return nil }
    let element2 = collection[index]
    let pair = [element1,element2]
    return C(pair)
  }
}

do {
  print("Pairs from array")
  let array = ["A","B","C"]
  let pairs = Pairs(array) //This line is fine
  for pair in pairs {
    print(pair)
  }
}

do {
  print("Pairs from set")
  let set = Set(["A","B","C"])
  let pairs = Pairs(set) // This line causes error
  for pair in pairs {
    print(pair)
  }
}

“letpairs = Pairs(set)”行会生成错误: “参数类型‘Set’不符合预期类型‘RangeReplaceableCollection’”

所以我需要弄清楚如何在不使用 RangeReplaceableCollection 的情况下实例化集合?

最佳答案

您从未限制 CollectionType 的类型,所以 Swift 根本不知道你可以创建一个,更不用说通过传递数组来创建一个了。 Collection本身不 promise 任何init方法也可以。我们需要去RangeReplaceableCollection得到这个:

struct AnyMaker<CollectionType>: Sequence, IteratorProtocol
where CollectionType: RangeReplaceableCollection {
    typealias Input = CollectionType.Element

    ...
}

完成后,next()看起来像这样:

mutating func next() -> CollectionType? {
    switch stage {
    case .a:    stage = .ab;   return CollectionType([a])
    case .ab:   stage = .end;  return CollectionType([a,b])
    case .end:                 return nil
    }
}

请注意,这会返回 CollectionType?不是CollectionType<Input>? 。没有关于 CollectionType要求它接受一个类型参数,所以我们不能传递一个。即使我们想要它,也无法表达“采用类型参数”,但我们不想要它。 CollectionType只需要一些Element ,这是 RangeReplaceableCollection 所 promise 的.

let anyMaker = AnyMaker<[String]>(a: "A", b: "B")
for x in arrayMaker {
    print(x)
}

完整代码:

struct AnyMaker<CollectionType>: Sequence, IteratorProtocol
where CollectionType: RangeReplaceableCollection {
    typealias Input = CollectionType.Element
    var a,b: Input
    var stage = Stage.a

    init(a: Input, b: Input) {
        self.a = a
        self.b = b
    }

    mutating func next() -> CollectionType? {
        switch stage {
        case .a:    stage = .ab;   return CollectionType([a])
        case .ab:   stage = .end;  return CollectionType([a,b])
        case .end:                 return nil
        }
    }
}

关于swift - 返回泛型集合的迭代器 - Swift 4.2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53180755/

相关文章:

ios - 为什么在关闭模态视图 Controller 后从 View 中删除 CAGradientLayer

swift - 有没有办法在 RealityKit 中将 View 渲染为实体?

ios - 接受类型序列的函数

swift - 如何在 Swift 上为堆栈声明 "if optional"

.Net BindingDictionary

c# - 如何在不同类型的集合之间进行匹配?

ios - View Controller 转换的 3 种方式

swift - Swift 3 中的 Firebase 语法

java - 在 map 上强制执行泛型

java - 使用 Guava ForwardingList 装饰集合的意外行为