0

我学得很快。我想使用一个自定义类来循环[能够 for...in 循环],如 Array。以下是迄今为止我尝试过的给定示例代码。有问题的课程是“GuestManager”,它持有客人的私人集合 [Guest 类的对象]

import Foundation

class Guest{
    var guestId: String
    var guestName: String

    init(gId: String, name: String){
        self.guestId = gId
        self.guestName = name
    }
}

class GuestManager: GeneratorType, SequenceType{
    private var guests = [Guest]?()
    private var nextIndex: Int

    init(guests: [Guest]){
        self.guests = guests
        self.nextIndex = 0
    }

    func next() -> Guest? {
        if  self.nextIndex > (self.guests?.count)! - 1 {
            self.nextIndex = 0
            return nil
        }
        let currentGuest = self.guests![self.nextIndex]
        self.nextIndex += 1
        return currentGuest
    }
    subscript(aGuestId gID: String) -> Guest{
        return (self.guests?.filter({$0.guestId == gID}).first)!
    }
}

我不想创建符合 GeneratorType 和 SequenceType 协议的单独类。相反,我创建了一个符合这两种协议的类。

以下是我的一些问题:

  1. 我想知道这是否是拥有自定义集合类型的正确方法?

  2. 我们可以使用下标作为一种基于属性执行搜索的方法,例如上面示例代码中的“subscript(aGuestId gID: String)”吗?

  3. 从上面示例代码中的 next() 函数实现的代码中可以清楚地看出,当迭代结束时重置“nextIndex”。如何处理我们在 for...in 循环中使用 break 语句的情况,如下所示:

    for aGuest in guestManager{//guestManager an instance of GuestManager class instantiated with several guest objects
        print(aGuest.guestName)
    }
    for aG in guestManager{
        print(aG.guestId)
        break
    }
    

    在第二个 for 循环中,代码在获取第一个 Element [在这种情况下为来宾对象] 后中断。随后的 for 循环将从集合中的索引 1 开始,而不是从 0 开始。无论如何要处理这种中断情况,以便对于每个后续的 for 循环,索引始终设置为 0?

谢谢

编辑:似乎可以使用以下代码修复“nextIndex”重置问题[在 GuestManager 类中添加]用于 generate() 方法实现

func generate() -> Self {
        self.nextIndex = 0
        return self
    }
4

2 回答 2

2

您不应该将内容存储nextIndex在类中。您可以在方法中使用局部变量,generate然后让该变量被传递给您在该方法中创建的生成器的闭包中捕获。这就是您需要采用的全部内容SequenceType

class GuestManager: SequenceType{
    private var guests: [Guest]

    init(guests: [Guest]) {
        self.guests = guests
    }

    func generate() -> AnyGenerator<Guest> {
        var nextIndex = 0
        return AnyGenerator {
            guard nextIndex < self.guests.endIndex else {
                return nil
            }
            let next = self.guests[nextIndex]
            nextIndex += 1
            return next
        }
    }
}

对于下标,您应该采用Indexable. 实际上,满足您所有要求的最简单方法是将尽可能多的 、 和最终(如果您想支持它)逻辑传递SequenceTypeIndexableCollectionType的阵列,该阵列已经具有这些功能。我会这样写:

class GuestManager {
    private var guests: [Guest]

    init(guests: [Guest]){
        self.guests = guests
    }
}

extension GuestManager: SequenceType {
    typealias Generator = IndexingGenerator<GuestManager>

    func generate() -> Generator {
        return IndexingGenerator(self)
    }
}

extension GuestManager: Indexable {
    var startIndex: Int {
        return guests.startIndex
    }

    var endIndex: Int {
        return guests.endIndex
    }

    subscript(position: Int) -> Guest {
        return guests[position]
    }
}

更多观察:

  1. 您的guests属性不应该是可选的。它使代码更复杂,没有任何好处。我在我的代码中相应地更改了它。
  2. 您的Guest类可能应该是值类型(结构)。GuestManager也是结构的良好候选者,除非您需要类的引用语义(标准库中的所有集合类型都是结构)。
于 2016-05-05T14:08:54.067 回答
0

我认为您在这里尝试的下标方法有点复杂。就个人而言,为了清楚起见,我会使用一个函数来做到这一点。

guestManager[aGuestId: guestId]

guestManager.guestWithID(guestId) 

所以从风格上讲,我可能会选择这样的东西

import Foundation

class Guest{
  var guestId: String
  var guestName: String

  init(guestId: String, guestName: String){
    self.guestId = guestId
    self.guestName = guestName
  }
}

class GuestManager: GeneratorType, SequenceType{
  private var guests: [Guest]
  private var nextIndex = 0

  init(guests: [Guest]){
    self.guests = guests
  }

  func next() -> Guest? {
    guard guests.count < nextIndex else {
      nextIndex = 0
      return nil
    }

    let currentGuest = guests[nextIndex]
    nextIndex += 1
    return currentGuest
  }

  func guestWithID(id: String) -> Guest? {
    return guests.filter{$0.guestId == id}.first ?? nil
  }
}
于 2016-05-05T14:07:50.070 回答