[Swift]extensionで実装するPerl風の配列操作 

[swiftで定義するperl風な配列操作](http://qiita.com/worthmine/items/9d335ce983c04ec15359)の延長で```splice```とかささっと実装しようかと思ったんですけど、```endIndex```とかから全て実装せねばいけないらしく、面倒だったので```Array```から継承させようとトライして失敗し、「あれ？コレは```extension```を利用する事例では？」と思い、その路線で攻めてみたらビルド通りましたので共有します。

##Source

```ExtensionArrayLikePerl.swift
extension Array {
    typealias Element = T
    
    mutating func scalar() -> Int { // use it if you like perl
        return Int(self.count)
    }
    
    mutating func pop() -> T? {
        return self.isEmpty ? nil : self.removeAtIndex(self.endIndex.predecessor())
    }
    
    mutating func push(newElements: T...) -> [T] {
        self.splice(newElements, atIndex: self.endIndex)
        return self
    }
    
    mutating func shift() -> T? {
        return self.isEmpty ? nil : self.removeAtIndex(self.startIndex)
    }
    
    mutating func unshift(elements: T...) -> [T] {
        self.splice(elements, atIndex: self.startIndex)
        return self
    }
    
    mutating func splice(var _ atIndex :Int = 0, _ length :Int = 0, _ newElements: T...) -> Slice<T>? {
        description
        var theIndex = length + atIndex
        var spliced :Slice<T> = []
        if length < 0 {fatalError("minus length was set")}
        if atIndex >= 0 {
            if theIndex > self.endIndex {fatalError("Bad Access")}
            let preArray = atIndex > 0 ? self[self.startIndex..<atIndex] : []
            spliced = length > 0 ? self[atIndex..<theIndex] : []
            let postArray = self[theIndex..<self.endIndex]
            self = preArray + Array(newElements) + postArray
            return length > 0 ? Slice(spliced) : nil
        } else {    // you can use minus atIndex because it is like Perl
            let reversed = self.reverse()
            atIndex = abs(atIndex + 1)
            theIndex = length + atIndex
            if theIndex > self.endIndex {fatalError("Bad Access")}
            let postArray = atIndex > 0 ? reversed[reversed.startIndex..<atIndex].reverse() : []
            spliced = length > 0 ? reversed[atIndex..<theIndex].reverse() : []
            let preArray =   theIndex < reversed.endIndex ? reversed[theIndex..<reversed.endIndex].reverse() :[]
            self = preArray + Array(newElements) + postArray
            return length > 0 ? Slice(spliced) : nil
        }
    }
}
```
##Usage
下記のように利用できます

```
// Use like bellow
var a :Array = ["Four", "Seven", "Eight" ]
a.splice(["Five", "Six"], atIndex: 1)   // using a default splice
a.splice(2, 0, "Five2" )                 // -> nil   //use splice with no adding. it returns nil but sucsesses to splice
a.splice(2, 2, "Six3", "Seven2")        // -> {["Five2", "Six"]}  // using mutating splice
a.splice(-4, 1, "Six4" )                // -> {["Six3"]}  // use a added splice
a                                       // -> ["Four", "Five", "Six4", "Seven2", "Eight"]

a.splice(0, a.count, "other", "Strings", "like", "those")
a                           // -> ["other", "Strings", "like", "those"]
a.splice(-2, 2)             // -> ["Strings", "like"]

a = ["Four", "Five", "Six", "Seven", "Eight" ]
a.unshift("Two", "Three")           // insert an array to the top of this Array
a.unshift("One")                    // add a value to the top of this Array
a.count                             // -> 8
a.push("Nine", "Ten")               // add an array to the bottom of this Array
a.push("Eleven")                    // add a value to the bottom of this Array
a[2]                                // -> "Three"
a[2...3]                            // -> "Three", "Four"
a                                   // -> ["One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Eleven"]
a.count                             // -> 11
a.shift()                           // remove one value from the top of this Array
a.pop()                             // remove one value from the bottom of this Array
a.count                             // -> 9

// for Int
var b :Array = [4, 7, 8 ]       // -> [4,7,8]
b.count                         // -> 3
b.splice([5, 6], atIndex: 1)    // -> [4,5,6,7,8]
b.unshift(2, 3)[0...0]          // -> [2]
var unshifted = b.unshift(1)    // -> [1,2,3,4,5,6,7,8]
unshifted.unshift(0)            // -> [0,1,2,3,4,5,6,7,8]
b                               // -> [1,2,3,4,5,6,7,8]
b.push(9, 10)[1...3]            // -> [2,3,4]
b.push(11)[b.startIndex]        // -> 1
b[2]                            // -> 3
b.shift()                       // -> {Some 1}  // because the Type has been never defined

var shifted = b.shift()!        // -> 2 // it must be bad at grammar because pop and shift may return nil
b.splice(0, b.count-2)          // splice 7 elements with no adding it's the very Perl-like!
var popped :Int! =  b.pop()     // -> 11    // it will be a better way
popped =  b.pop() as Int?       // -> 10    // how to down cast
b.count                         // -> 0     // it means this Array is Empty
popped =  b.pop() as Int?       // -> nil   //pop and shift will return nil if there is no value
```
##Tips
~~ちなみに、単にSwiftのArrayを拡張しただけなので、型の混在する配列は作れませんでした。~~[作れます。こちらに詳しくまとめました。](http://qiita.com/worthmine/items/e1bde90f0fea60af3f9b) 

~~なお、perl風に```splice```で配列の追加も担うのは```override```か何かでできそうですが、**正規のメソッドを上書きするデメリットも考えないといけない**ので絶賛保留中です。~~
**```override```できませんでしたので```mutating```で実装しました。**

マイナスの値が```length```に代入されるケースには```fatalError```で対応し、```atIndex```にマイナスの値が代入されるのはPerl風に後ろからのインデックスとみなす方向で~~許容する予定です。~~**[実装しました。結構大仕事だったので別記事にまとめました](http://qiita.com/worthmine/items/e859e87d6d46355bd069)**。

```return self```のメリットを見つけました。

```
var b :Array = [4, 7, 8 ]       // -> [4, 7, 8]
b.count                         // -> 3
//のとき、
b.push(9, 10)[1...3] // -> [7, 8, 9]
b.push(11)[b.endIndex.predecessor()]    // -> 11
```

のような添え字で返り値にアクセスできることです。ちょっぴりPerl-Likeで感動しました。

~~今悩んでいるのは、```pop```や```unshift```が```nil```を返すことの是非です~~[コメントいただき解決しました](http://qiita.com/worthmine/items/40bfdd8f1f75bfe3463a#comment-faf445ccbbbb3c2c99f4)
 初期化時に```nil```が入るケース、または後から```nil```が混入するケースを想定しましたがきちんとエラーになるところまで確認を終えました。

```
var forNil = [nil, nil, nil] // Cannot convert the expression's type 'Array' to type 'NilLiteralConvertible'
a.unshift(nil) // Type '(String...)' does not conform to protocol 'NilLiteralConvertible'
b.unshift(nil,nil)  // Type 'Int' does not conform to protocol 'NilLiteralConvertible'
b.splice(0, 0, nil) // Type 'Int' does not conform to protocol 'NilLiteralConvertible'
```

本件に関しては以上だと思いますが[```splice```に関してバージョンアップがあった場合](http://qiita.com/worthmine/items/e859e87d6d46355bd069)は適宜本稿でも対応しようと思います。

##github
[worthmine/Swift-Extension-Array-like-Perl](https://github.com/worthmine/Swift-Extension-Array-like-Perl)