arrays - 如何扩展特定类型数组的数组功能?

标签 arrays swift class swift2

(使用我常用的扑克牌示例)
我正在尝试制作一个通用的 CardCollection两者都是Deck和一个 Hand将继承自。牌组和手牌都需要排序或洗牌,但会有一些差异,例如初始化以及是否删除 Card 的方法。在其他地方使用的是 Deal (对于 Deck ), Play ,或Discard (对于 Hand s)。

class CardCollection: <Some protocol or another that Arrays use> {
    var collective = [Card]()
    // CardCollection-specific functions

    // pass-through functions
    func append(newCard: Card) {
        collective.append(newCard)
    }
}


class Deck: CardCollection {
    // deck-specific functions
}
class Hand: CardCollection {
    // hand-specific functions
}

我目前实现它的方式(见上文)是使用一个包含卡片数组的类,但是如果不编写大量的传递函数来获取我的类,我就无法像数组一样使用我的类以数组形式遵守所有协议(protocol)。

我需要的是一种让我可以做类似 for card in deck 之类的事情的方法(就好像 deck 只是一个 Array<Card> ),而无需编写大量包装函数来获取 CardCollection遵守所有必要的协议(protocol)。

如何制作一个功能就像 Array<Card> 的 CardCollection无需对 Array 协议(protocol)使用的每个函数都创建传递函数用途?

最佳答案

您可以定义一个 CardCollection 协议(protocol),该协议(protocol)继承自 RangeReplaceableCollectionType, 以及具有默认实现的协议(protocol)扩展以转发所有 访问底层collective数组的方法:

struct Card { 
    // Simplified for demonstration purposes:
    let rank : Int
    let suit : Int
}

protocol CardCollection : RangeReplaceableCollectionType {
    var collective : [Card] { get set }
}

extension CardCollection  {

    var startIndex : Int { return collective.startIndex }
    var endIndex : Int { return collective.endIndex }

    subscript(position : Int) -> Card {
        get {
            return collective[position]

        }
        set(newElement) {
            collective[position] = newElement
        }
    }

    mutating func replaceRange<C : CollectionType where C.Generator.Element == Card>(subRange: Range<Int>, with newElements: C) {
        collective.replaceRange(subRange, with: newElements)
    }
}

然后

struct Deck: CardCollection {
    var collective = [Card]()

}

struct Hand: CardCollection {
    var collective = [Card]()

}

两者都符合RangeReplaceableCollectionType并且可以被处理 就像一个数组:

var deck = Deck()
deck.append(Card(rank: 1, suit: 1))
deck[0] = Card(rank: 2, suit: 3)

for card in deck {
    print(card)
}

var hand = Hand()
hand.append(deck.first!)

如果Deck/Hand而不是结构,那么它们 需要是final或者有一个必需的init()方法, 比较 Why use required Initializers in Swift classes? .


更一般一点,您可以定义一个ElementCollection 协议(protocol)(独立于类型) 其行为类似于数组(通过符合 RangeReplaceableCollectionType)并将访问权限转发到 底层 elements 数组:

protocol ElementCollection : RangeReplaceableCollectionType {
    typealias Element
    var elements : [Element] { get set }
}

extension ElementCollection  {

    var startIndex : Int { return elements.startIndex }
    var endIndex : Int { return elements.endIndex }

    subscript(position : Int) -> Element {
        get {
            return elements[position]

        }
        set(newElement) {
            elements[position] = newElement
        }
    }

    mutating func replaceRange<C : CollectionType where C.Generator.Element == Element>(subRange: Range<Int>, with newElements: C) {
        elements.replaceRange(subRange, with: newElements)
    }
}

然后用作

struct Card { 
    // Simplified for demonstration purposes:
    let rank : Int
    let suit : Int
}

struct Deck: ElementCollection {
    var elements = [Card]()

}

struct Hand: ElementCollection {
    var elements = [Card]()

}

关于arrays - 如何扩展特定类型数组的数组功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34237047/

相关文章:

c++ - 模板-无法将函数定义与现有声明c++匹配

c++ - 无法在成员函数本身中声明派生数据类型指针变量

javascript - Coffeeescript : how to declare private function that can be used from within Array. 减少?

javascript - jQuery parseJSON 多维数组

ios - 找不到框架 FirebaseCore

ios - 从嵌入式 View Controller 传回数据

javascript - 根据值从一个数组中删除对象(如果存在于另一数组中)

c - 将BMP图像放入2D数组并在C中编辑RGB值

ios - Swift Admob 插页式错误

javascript - TypeScript 中的多类继承