Pebble Coding

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

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はいらねえと思います。

swfit/rust 負数の除法

swift,C,Javaとruby, python,perlでは、 負数を割り算や剰余に使った場合、結果が異なる。

python 剰余

7 % 3 -> 1
7 % -3 -> -2
-7 % 3 -> 2
-7 & -3 -> -1

swift 剰余

7 % 3    -> 1
7 % -3   -> 1
-7 % 3   -> -1
-7 % -3  -> -1

python 商

7 / 2 -> 3
7 / -2 -> -4
-7 / 2 -> -4
-7 / -2 -> 3

swift 商

7 / 2 -> 3
7 / -2 -> -3 
-7 / 2  -> -3
-7 / -2  -> 3

swiftの除法をユークリッド除法と呼び、 剰余を割られる値のsignに合わせる。

pythonの除法を絶対的最小剰余と呼び、割り切れない場合はマイナス無限大方向に丸める。

除法 - Wikipedia

rust

rustはc/swift/java系統と同じである。

7 % 3    -> 1
7 % -3   -> 1
-7 % 3   -> -1
-7 % -3  -> -1
7 / 2 -> 3
7 / -2 -> -3 
-7 / 2  -> -3
-7 / -2  -> 3

なお、BigIntも同じ。

rustでpython,haskelと同じようにするには、divremクレートのDivFloor,RemFloorを使えばよい。

ios10.3 ファイルパス問題

環境 ios10.3.1
Xcode 8.3.2

        guard let path:String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
            return
        }
        let filename0 = path + "/" + "a.txt"
        if let fp0 = fopen(filename0, "wb") {
            print("fp0 \(fp0)")
        } else {
            print("fp0 is nil")
        }
        
        let filename1 = path + "/" + "ぱ.txt"
        if let fp1 = fopen(filename1, "wb") {
            print("fp1 \(fp1)")
        } else {
            print("fp1 is nil")
        }
        
        let fm = FileManager.default
        try? fm.createDirectory(atPath: path + "/ぱ", withIntermediateDirectories: true, attributes: nil)
        
        let filename2 = path + "/ぱ/" + "ぴ.txt"
        if let fp2 = fopen(filename2, "wb") {
            print("fp2 \(fp2)")
        } else {
            print("fp2 is nil")
        }
        
        let filename3 = path + "/ぱ/" + "b.txt"
        if let fp3 = fopen(filename3, "wb") {
            print("fp3 \(fp3)")
        } else {
            print("fp3 is nil")
        }
        
        let filename4 = (filename3 as NSString).fileSystemRepresentation
        if let fp4 = fopen(filename4, "wb") {
            print("fp4 \(fp4)")
        } else {
            print("fp4 is nil")
        }
[結果]
fp0 0x0000000100d01c78
fp1 0x0000000100d11808
fp2 is nil
fp3 is nil
fp4 0x0000000100c16da8

fopenでのファイル作成では、濁点、半濁点名を付けたフォルダ名をパスに含むとfopenに失敗するようです。
fopenに渡す場合はNSStringのfileSystemRepresentationで変換すればよいようです。

参考:

https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/APFS_Guide/FAQ/FAQ.html#//apple_ref/doc/uid/TP40016999-CH6-DontLinkElementID_3:Apple APFS Guide

iOS10.3のファイルパス問題について