【问题标题】:How to extend Array functionality for arrays of a specific type?如何为特定类型的数组扩展 Array 功能?
【发布时间】:2015-12-12 06:31:50
【问题描述】:

(以我常用的扑克牌为例)
我正在尝试制作一个通用的CardCollectionDeckHand 都将从中继承。甲板和手牌都需要排序或洗牌,但会有一些差异,例如初始化以及删除Card以供其他地方使用的方法是否为Deal(对于Deck)、Play、或Discard(用于Hands)。

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
}

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

我需要的是一种方法,它可以让我做for card in deck 之类的事情(好像deck 只是一个Array&lt;Card&gt;),而不需要编写大量的包装函数来让CardCollection 符合所有必要的协议。

如何制作一个像 Array&lt;Card&gt; 一样运行的 CardCollection,而不对 Array 使用的协议使用的每个函数进行传递函数?

【问题讨论】:

    标签: arrays swift class swift2


    【解决方案1】:

    您可以定义一个继承自的CardCollection 协议 RangeReplaceableCollectionType, 和一个带有默认实现的协议扩展来转发所有 底层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 或有required init() 方法, 比较 Why use required Initializers in Swift classes?.


    稍微通用一点,你可以定义一个ElementCollection 协议(独立于Card 类型) 它的行为就像一个数组(通过符合 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]()
    
    }
    

    【讨论】:

    • 澄清一下:我仍然需要为所有在我的协议扩展中列出on the documentation page for Range ReplacableCollectionType 的方法提供转发,对吧?
    • @cjm:不,只有那些没有默认实现的。上面的示例仅实现了 startIndex、endIndex、下标(来自 Indexable 协议)和 replaceRange 的转发。其他方法的默认实现,例如 first、append 或 generate(用于 for .. in),然后使用这些方法。
    • 那么我一定错过了一些没有默认实现的东西(很可能是协议扩展),因为它抱怨Type 'Deck' does not conform to protocol 'RangeReplaceableCollectionType'。没关系(以上内容):我很傻,忘记在问题导航器中展开问题以获取详细信息
    猜你喜欢
    • 2018-03-19
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多