Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

swift3 IntegerArithmaticプロトコル

IntegerArithmeticプロトコルを実装するには、以下8つの関数を定義する必要がある。 最初の2つはComparableである。

static func ==(lhs: M, rhs: M) -> Bool
static func <(lhs: M, rhs: M) -> Bool
static func addWithOverflow(_ lhs: M, _ rhs: M) -> (M, overflow: Bool) 
static func subtractWithOverflow(_ lhs: M, _ rhs: M) -> (M, overflow: Bool) 
static func multiplyWithOverflow(_ lhs: M, _ rhs: M) -> (M, overflow: Bool) 
static func divideWithOverflow(_ lhs: M, _ rhs: M) -> (M, overflow: Bool) 
static func remainderWithOverflow(_ lhs: M, _ rhs: M) -> (M, overflow: Bool) 
func toIntMax() -> IntMax

最後の一つはswiftの最大Int(=UInt64)へ変換するものである。 このプロトコルを実装すると以下の5つの演算や関連する演算ができるようになる。

public static func +(lhs: Self, rhs: Self) -> Self
public static func -(lhs: Self, rhs: Self) -> Self
public static func *(lhs: Self, rhs: Self) -> Self
public static func /(lhs: Self, rhs: Self) -> Self
public static func %(lhs: Self, rhs: Self) -> Self

このプロトコルを用いると、通常とは異なる演算規則を持つ整数を作ることができる。 複素整数や桁数が無制限の整数などを自作することができる。

swift3 Comparableプロトロル

Comparableプロトコルを作るには、
static func <(lhs: Even, rhs: Even) -> Bool
static func ==(lhs: Even, rhs: Even) -> Bool
の2つを実装すればよい。

struct M : Comparable 
{
    var val:Int
    
    static func <(lhs: M, rhs: M) -> Bool 
    {
        return lhs.val < rhs.val
    }
    
    static func ==(lhs: M, rhs: M) -> Bool
    {
        return lhs.val == rhs.val
    }
}

let r1 = M(val:1)
let p1 = M(val:2)
assert(r1 < p1)

let r2 = M(val:1)
assert(r1 == r2)

swift3 Collectionプロトコル

Collectionプロトコルを作るには、
startIndexプロパティ,endIndexプロパティ,subscript,index(after:) の4つを実装する必要がある。
Collection - Swift Standard Library | Apple Developer Documentation

ここでは奇数を返すコレクションOddを作ってみた。

struct Odd : Collection {
    var startIndex: Int
    var endIndex: Int
    subscript(i: Int) -> Int {
        return 1 + 2 * i  
    }
    func index(after: Int) -> Int {
        return after + 1
    }
}

let odd = Odd(startIndex:1, endIndex:4)
for i in odd {
    print("\(i)")
}
3
5
7

swift3 Sequenceプロトコル

Sequenceプロトコルの例 ここでは1以上の奇数を順番に返すものを作ってみた。ちなみにIntの範囲を超えるとクラッシュするが気にしないでもらいたい。(^ ^)

struct Odd : Sequence, IteratorProtocol {
    typealias Element = Int
    private var v:Element = 1
    public mutating func next() -> Element? {
        defer { v += 2 }
        return v
    }
}

var odd = Odd()
for _ in 0..<5 {
    print("\(odd.next())")
}

結果

Optional(1)
Optional(3)
Optional(5)
Optional(7)
Optional(9)

swift preconditionとassertの違い

swiftにはassertさせる関数がいっぱいあって困ります。

1) assert()

let ary = [1, 2, 3]
let i = 3
assert(i < ary.count)
print("\(ary[i])")

assertion failed: file /develop/aaa/aaa/ViewController.swift, line 18

2) precondition()

let ary = [1, 2, 3]
let i = 3
precondition(i < ary.count)
print("\(ary[i])")

precondition failed: file /develop/aaa/aaa/ViewController.swift, line 18

3) fatalError()

let ary = [1, 2, 3]
let i = 3
if i < ary.count {
} else {
    fatalError()
}
print("\(ary[i])")

fatal error: file /develop/aaa/aaa/ViewController.swift, line 19

1) -> 2) -> 3) の順番で致命的なエラーになっていくようです。 fatalErrorはコンパイラがその部分での戻り値の存在チェックをしなくなるので、仮の戻り値を書かずに済みます。

正直な感想として、preconditionはいらねえと思います。