简体   繁体   English

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

[英]How to extend Array functionality for arrays of a specific type?

(Using my usual playing card example) (使用我通常的扑克牌示例)
I am trying to make a generic CardCollection that both a Deck and a Hand would inherit from. 我正在尝试制作一个普通的CardCollectionCardCollection DeckHand都会从中继承。 Both Decks and Hands would need to be sorted or shuffled, but there would be some differences such as initialisation and whether the method for removing a Card for use elsewhere is Deal (for a Deck ), Play , or Discard (for Hand s). 两个卡座和双手将需要进行排序或改组,但仍然会有一些差别,如初始化以及是否用于去除方法Card其他地方使用的Deal (对于Deck ), PlayDiscard (对于Hand或多个)。

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
}

The way I'm currently implementing it (see above) is with a Class that contains an Array of Cards, but I can't use my classes like they were Arrays without writing tons of pass-through functions to get my classes to conform to all the protocols as an Array. 我当前实现它的方式(见上文)是使用包含卡片数组的类,但是如果不编写大量的传递函数来使我的类符合我的要求,就无法使用它们像数组那样的类所有协议都作为数组。

What I need is a way that lets me do things like for card in deck (as if deck were simply an Array<Card> ) without writing tons and tons of wrapper functions just to get the CardCollection to conform to all the necessary protocols. 我需要的是一种方法,让我可以for card in deck (就像deck组只是Array<Card> ),而无需编写大量包装函数来使CardCollection符合所有必需的协议。

How do I make a CardCollection that functions like it's just an Array<Card> without making pass-through functions on every function used by the protocols that Array uses? 如何制作功能类似于Array<Card>的CardCollection,而不对Array使用的协议使用的每个功能都进行传递功能?

You can define a CardCollection protocol which inherits from RangeReplaceableCollectionType , and a protocol extension with default implementations to forward all access methods to the underlying collective array: 您可以定义从RangeReplaceableCollectionType继承的CardCollection协议,以及带有默认实现的协议扩展,以将所有访问方法转发到基础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)
    }
}

Then 然后

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

}

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

}

both conform to RangeReplaceableCollectionType and can be treated like an array: 两者都符合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!)

If Deck / Hand are classes instead of structs then they need to be final or have a required init() method, compare Why use required Initializers in Swift classes? 如果Deck / Hand而不是结构,则它们必须是final或具有required init()方法,请比较为什么在Swift类中使用必需的Initializers? .


Slightly more general, you can define an ElementCollection protocol (independently of the Card type) which behaves like an array (by conforming to RangeReplaceableCollectionType ) and forwards the access to an underlying elements array: 稍微概括一点,您可以定义一个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)
    }
}

Which is then used as 然后用作

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

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

}

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM