Swift 2: Расширения протоколов

Swift 2: Расширения протоколов

Одна из самых замечательных возможностей, которая появилась в Swift 2 - это расширения протоколов. Она позволяет вам добавлять новые методы ко всему что угодно, что реализует протокол. Мы подумали, что это может быть интересным и решили рассмотреть практический пример, в котором мы генерируем рандомные или повторяющиеся последовательности из коллекции.

Управлять этим очень просто. У нас есть коллекция и мы можем выбрать рандомно какое-то количество элементов для воспроизведения или установить повтор на определенное количество повторений. Мы можем выбрать любой вариант, но с возможностью управления остановкой при необходимости.

Теперь мы можем очень просто добавить новые методы в реализаторы протокола:

extension CollectionType {
    func randomSequence()->ProxySequence{
        return ProxySequence(self, length: nil, random:true)
    }
    
    func repeatingSequence()->ProxySequence{
        return ProxySequence(self, length: nil)
    }

    func randomSequence(length  length:Int)->ProxySequence{
        return ProxySequence(self, length: length, random: true)
    }
    
    func repeatingSequence(length length:Int)->ProxySequence{
        return ProxySequence(self, length: length)
    }
}

Эти четыре метода достаточно простые (мы бы могли использовать дефолтные параметры, чтобы их было всего 2, принимая опциональную length равной nil, но семантика кажется некорректной. При чтении кода должно быть очевидным: хотим мы показать length или нет.)

Теперь все то, что реализует CollectionType будет иметь эти четыре метода (символы строки, сеты, массивы, словари или любой другой вид коллекции, который вы создадите сами).

Сюда мы включим реализацию ProxySequence и связанный с ним GeneratorType, но на самом деле это не является целью данной статьи. Но если вам интересно, обязательно прочитайте!

struct ProxySequence : SequenceType{
    let contents : C
    let length   : Int?
    let random   : Bool
    
    init(_ contents:C, length:Int?, random:Bool = false){
        self.contents = contents
        self.length   = length
        self.random   = random
    }
    
    func generate() -> ProxySequenceGenerator {
        return ProxySequenceGenerator(contents, length: length, random: random)
    }
}
struct ProxySequenceGenerator : GeneratorType{
    let elements: [C.Generator.Element]
    let length: Int?
    var index = 0
    let random: Bool
    
    init(_ contents: C, length: Int?, random: Bool){
        
        self.length = length
        self.random = random
        
        var elements = Array()
        
        for elementIndex in contents.enumerate(){
            elements.append(elementIndex.element)
        }

        self.elements = elements
    }
    
    mutating func next() -> C.Generator.Element? {
        if let length = length where index == length{
            return nil
        }
        
        defer{
            index++
        }
        
        if random{
            return elements[Int(arc4random()) % elements.count]
        } else {
            return elements[index % elements.count]
        }
    }
}

Теперь вы можете делать некоторые трюки, например, генерировать рандомные символы из строки.

for character in "hello-world".characters.randomSequence(length: 5){
    character
}

Или рандомные простые числа массива

for prime in [1,2,3,5,7].randomSequence(length: 5){
    prime
}

Или повторяющиеся последовательности строк из элементов словаря.

for even in [0,2,4,6,8].repeatingSequence(length: 10){
    even
}

Мы думаем, что вы оцените эти новые мощные возможности!

Оригинал: http://www.swift-studies.com/blog/2015/6/15/exploring-swift-2-protocol-extensions