kentana20 技忘録

技術ネタを中心に、セミナー、勉強会、書籍、会社での出来事を綴っていきます。不定期更新。

詳解Swift#1(chapter1~2)

7月下旬までの3ヶ月でアプリ1本作るために、Swift再入門する。 GWで詳解Swift進捗させたいので、Chapterごとのまとめを書いておく。

詳解 Swift 改訂版

詳解 Swift 改訂版

chapter1 Swiftでプログラミング

1章は型とか、変数、定数、構文、プレイグラウンドなどの第一歩的な話なので部分的に掻い摘んで書く。

データ型

種類 型名 説明
整数型 Int 整数全般はコレ
整数型 UInt 符号なし整数
実数型 Float 浮動小数
実数型 Double 高精度浮動小数
論理型 Bool true/false
文字 Character Unicodeの1文字
文字 UnicodeScalar Unicode文字コード
文字列 String Unicode文字列

変数 / 定数 / 文字列 / 配列

  • 変数: var
    • var x: 型 = 初期値 で書く
  • 定数: let
    • let y: 型 = 代入値 で書く

型推論が使えるので、型は省略可能。

  • 文字列

  • print

    • print(xxxx) で標準出力に書ける
    • separator: "" , terminator: "" で区切りと最終文字を定義できる
  • 配列

    • var a : [Int] = [1,2,3,4,5]
    • var s : [String] = []

制御構文

  • while
var i = 1, j = 2
while i < 2 {
    ++i
}
  • repeat-while
var n = 10
repeat {
    print("\(n) ", terminator:"")
    --n
} while n > 1
  • ラベル付き
let days = 31
let firstDay = 2
var w = 0

for ; w < firstDay; w++ {
    print("    ", terminator:"")
}

var d = 1
loop: while true {
    for ; w < 7; w++ {
        let pad = d < 10 ? " " : ""
        print(pad + "  \(d)", terminator:"")
        if ++d > days {
            print("")
            break loop
        }
    }
    print("")
    w=0
}

コマンドラインからSwift

  • swiftc
$ swiftc xxxx.swift

でバイナリ作れる。

chapter2 関数

関数定義

var total = 0

func count(n: Int) -> Int {
      total += n
          return total
}

func reset() { total = 0 }

呼び出すときは↓。戻り値を使わない場合は受け取らなくてもいい。

count(10)
var ret = count(5)
reset()
  • 外部引数名
func buyProduct(product: Int, price: Int, quantity: Int) {
    print("Product: \(product), amount: \(price*quantity)")
}

buyProduct(19090, price:18000, quantity:1)

第一引数は外部引数名を指定しない。 (指定するとコンパイルエラーになる)

Objective-C, Swiftの流儀として、 関数名には関数の役割+第一引数の意味を説明したものにする ため、第一引数に外部引数名を指定しないらしい。

  • 内部引数名
func area(height h: Double, width w: Double) -> Double {
    return h * w
}

area(height: 10.2, width: 1.5)
//area(10.2, width: 1.5) <- error
//area(width: 1.5, height: 10.2) <- error

外部引数名が指定されている場合は、呼び出し時の引数名指定が必須となる。 外部引数名を指定しているからといって、引数の順序を入れ替えられるわけではない。順番通りにしないといけない。

func areaNew(h: Double, _ w: Double) -> Double {
    return h*w
}

areaNew(10.2, 1.6)

第二引数の先頭に_をつけると、外部引数名の呼び出しを省略できる。呼び出し側を考えるとこれが一番シンプル。

  • 内部引数の省略
func compare(a:Int, _ b:Int, _:Bool) -> Bool {
    return a > b
}

compare(10, 15, true)

func compareX(a:Int, _ b:Int, option _:Bool) -> Bool {
    return a > b
}

compareX(10, 11, option: true)

インタフェースを揃えるために引数定義はするけど使わない場合は _:Bool のように内部引数名を省略できる。

_ は何とでも組み合わせて使えるワイルドカード。繰り返しの値を使わない場合とかに以下のように書ける。

for _ in 1...10 {
    print("hoge")
}

関数のいくつかの設定

  • inout引数 (参照渡し)
func mySwap(inout a:Int, inout b:Int) {
    let t = a; a = b; b = t
}

var x = 1; var y = 3

mySwap(&x, b: &y)

print(x, terminator:"")
print(y, terminator:"")

引数の値を関数内で変更する場合に inout を付与した引数を使う。その場合は関数呼び出し時に & を付けた変数を指定する必要がある。

  • 引数の既定値
let fontSize: Float = 12.0

func setFont(name: String, size: Float = fontSize, bold: Bool = false) {
    
    print("\(name) \(size)" + (bold ? "[B]" : ""))
}

setFont("ReglanPunch")
setFont("Times", size: 15.0, bold: false)
setFont("Times", bold: false, size: 15.0)

func setFontX(name: String, size: Float, bold: Bool) {
    print("\(name) \(size)" + (bold ? "[B]" : ""))
}

setFontX("Meryo", size: 16.0, bold: false)
//setFontX("Meryo", bold: false, size: 14.0) <- error

いわゆるoptional引数。既定値を定義しておくと呼び出し時に省略可能。optionalじゃないときは順番変えたらダメだったくせに、optionalのときは順番変えてもフツーに動く。書籍には既定値ありの引数についての制約みたいのがだ~っと書いてある。 こういうのはシンプルじゃなくてあまり好きじゃない。極力optional引数はナシでコード書きたい。

  • 引数の値を変更できるようにする
func dayOfWeek(var m:Int, _ d:Int, var year y:Int = 2016) -> Int {
    if m < 3 {
        m += 12; --y
    }
    let leep = y + y / 4 - y - y / 100 + y / 400
    return (leep + (13 * m + 8) / 5 + d) % 7
}
dayOfWeek(5, 9)

引数に var を付けると、関数内で引数を変更可能になる。付けない場合と let を付けた場合は関数内での変更は不可。 ちょっと構文的に複雑になる。

  • 関数のネスト
func printMonth(firstDay:Int, _ days:Int) {
    func daystr(d:Int) -> String {
        if d <= 0 {
            return "    "
        } else {
            return (d < 10 ? "   \(d)" : "  \(d)")
        }
    }
    
    var d = 1 - firstDay
    while d <= days {
        var line = ""
        for _ in 0 ..< 7 {
            line += daystr(d)
            if ++d > days { break }
        }
        print(line)
    }
}

printMonth(4, 31)
//daystr(1) <- error

クロージャ。この例で行くと daystr 関数は外部からは呼べない。とある関数内でしか使わない関数はこの記法で良い。

関数のオーバーロード

ここはコード無しで。

所感・雑感

半日ゆっくり読み進めた。序章感があったので、大きなトピックはなし。関数のOptionalの部分は少し違和感はあるものの、外部引数名のくだりは自分は結構好みかも。 しっかり読むと理解が進む。明日はもうちょい進捗させよう。