💯

競技プログラマのためのSwiftチートシート

2020/10/24に公開
4

Swift 未経験者が Swift で競技プログラミングに挑戦してみるための、 Swift の基本構文や標準ライブラリのチートシートです。競技プログラミングで必要そうなものに絞って掲載しています。より詳しい情報は公式ドキュメント "The Swift Programming Language" を御覧下さい。

本チートシートの各項目に素早くアクセスするには、ページ右下の "Contents" をご活用下さい。

Hello World

print("Hello, World!")

Swift では main 関数は必要ありません。 Python や Ruby のように↑の 1 行で完成されたコードです。

print の後はデフォルトで改行します。改行をなくすには次のように書きます。

print("Hello,", terminator: "") // 改行なし
print(" World!")

変数・定数

変数( var

変数宣言には var を使います。

var a = 42

変数には再代入可能です。

// 変数は再代入可
var a = 2
a = 3 // ✅ OK

Swift には型推論があるので型の記述を省略できますが、明記する場合は次のように : に続けて型を書きます。

var a: Int = 42

定数( let

定数宣言には let を使います。

let a = 42

定数には再代入できません

// 定数は再代入不可
let a = 2
a = 3 // ⛔ コンパイルエラー

定数宣言と初期化は別々にすることができ、条件分岐と組合せて初期化することも可能です。

// 条件分岐と定数の遅延初期化
let a: Int
if b < 100 {
    a = 2
} else {
    a = 3
}

演算子

基本的に C や Java などと同じです。ただし、インクリメントおよびデクリメントのための演算子 ++, -- は廃止されて利用できないので注意して下さい。

四則 & 剰余演算子( +, -, *, /, %

演算子 意味
+ たし算 2 + 3
- ひき算 3 - 2
* かけ算 2 * 3
/ わり算 6 / 2
% 剰余演算 8 % 3

整数( Int )同士のわり算の結果は Int に丸められる(切り捨て)ので注意して下さい。

7 / 2     // 3
7.0 / 2.0 // 3.5

Swift の演算子は関数なので、次のようにして高階関数の引数に渡すことができます。

// 1 から 100 までの合計(演算子を関数として利用)
let sum = (1 ... 100).reduce(0, +) // 5050

比較演算子( ==, !=, <, >, <=, >=

演算子 意味
== 等しい a == 2
!= 等しくない a != 2
< より小さい a < 2
> より大きい a > 2
<= 以下 a <= 2
>= 以上 a >= 2

Swift の演算子は関数なので、次のようにして高階関数の引数に渡すことができます。

// 演算子を関数として利用(降順にソート)
let descending = [2, 5, 3].sorted(by: >) // [5, 2, 3]

論理演算子( &&, ||, !

演算子 意味
&& かつ( AND ) 0 <= a && a < 100
` `
! 否定( NOT ) !(0 <= a && a < 100)

&& および || は短絡評価されます。

// 短絡評価
1 < 2 || isFoo() // 1 < 2 が true なので isFoo() は実行されない

ビット演算子( &, |, ~, ^

演算子 意味
& ビット単位 AND a & 0xff
` ` ビット単位 OR
~ ビット単位 NOT ~a
^ ビット単位 XOR a ^ b

シフト演算子( <<, >>

演算子 意味
<< 左シフト 1 << 16
>> 右シフト 1 << 16

複合代入演算子( +=, -=, *=, /= など)

演算子 意味
+= a += ba = a + b a += 100
-= a -= ba = a - b a -= 100
*= a *= ba = a * b a *= 100
/= a /= ba = a / b a /= 100

その他にも %=, &=, <<= など多様な複合代入演算子があります。

インクリメント( += 1 )、デクリメント( -= 1

Swift には ++ や -- のようなインクリメントおよびデクリメントのための演算子はないので、 +=-= を利用します。

a += 1 // インクリメント
a -= 1 // デクリメント

三項演算子( a ? b : c

// a < 100 が真なら "A" 、そうでなければ "B"
let result: String = a < 100 ? "A" : "B"

オーバーフロー( &+, &- など)

Swift の +- にはオーバーフローが許されていません。オーバーフローした場合は実行時エラーになります。意図的にオーバーフローさせたい場合には & を付けた &+, &- などの演算子を利用します。

let a: UInt8 = 0xFF
a &+ 1 // 0

基本的な型

整数( Int など)

let a: Int = 42

Swift の Int は実行環境によって 32 bit か 64 bit か変化しますが、 2020 年現在で Swift が動作する環境では基本的に 64 bit と考えて良いです。

今の環境でどちらかを調べるには次のようなコードを実行します。

// Int が 32 bit か 64 bit か確認
// 4 と表示されれば 32 bit
// 8 と表示されれば 64 bit
print(MemoryLayout<Int>.size)

環境によらず固定サイズの整数型もあり、標準で Int8, Int16, Int32, Int64 が用意されています。また、非負整数を表す UInt や、固定サイズ非負整数 UInt8, UInt16, UInt32, UInt64 もあります。 1 バイトを表すときは UInt8 を使います。

整数型の最大・最小値( .max, .min

static プロパティ max, min を使うことで、最大・最小値を取得できます。

// 最大・最小値の取得
Int.max    // 9223372036854775807
UInt16.max // 65535
Int8.min   // -128

整数型への変換

Swift は基本的に暗黙の型変換を許さないので、整数型同士であったとしても型変換が必要です。

// Int32 → Int の変換
let a: Int32 = 42
let b: Int = Int(a)

この Int16(a)キャストではなく、単に Int16 型のイニシャライザ(コンストラクタのようなもの)を呼び出しているだけです。整数型や浮動小数点数型は互いに変換できるように、変換のためのイニシャライザがそれぞれの型に用意されています。

String からの変換に失敗した場合(整数に変換できない文字列( "abc" など)が与えられた場合)、 nil が返されます。そのため戻り値の型は Int ではなく Int?Optional<Int> )になります。競プロでは失敗するような変換を行わないことが多いので、ほとんどのケースは ! を付けて nil を無視し、 Int に変換することができます。

// String → Int の変換
let s: String = "42"
let a: Int = Int(s)! // ! で nil を無視して Int? を Int に変換

整数リテラル( 42

let a = 0b101010 // 2 進数
let b = 0o52     // 8 進数
let c = 42       // 10 進数
let d = 0x2a     // 16 進数

桁数が多いときには、リテラル中に _ を挿入して可読性を向上することもできます。

let a = 1_000_000 // 100 万

Swift ではリテラル自体に型はありません。 ExpressibleByIntegerLiteral というプロトコルに適合した型であれば何でも整数リテラルで表すことができます。

// この場合、 42 というリテラルは UInt 型
let a: UInt = 42

これはリテラル 42Int 型で、それが UInt 型に暗黙の型変換されているのではありません。このリテラルが UInt 型の定数 a に代入されることから、コンパイラがリテラルの型を UInt に決定しています。

型の記述が省略された場合は、整数リテラルは Int 型と推論されます。

// この場合、 42 というリテラルは Int 型
let a = 42

浮動小数点数( Double など)

let a: Double = 42.0

Double は倍精度( 64 bit )浮動小数点数型です。単精度( 32 bit )浮動小数点数型の Float もありますが、競プロにおいて利用機会は少ないでしょう。

浮動小数点数型への変換

基本的に整数型と同じです。数値型同士でも明示的な型変換が必要です。

// Int → Double の変換
let a: Int = 42
let b: Double = Double(a)

String からの変換は失敗し nil が返されるおそれがあるので Double?Optional<Double> )となります。変換失敗が考えられない場合は ! を付けて nil を無視します。

// String → Double の変換
let s: String = "42.0"
let a: Double = Double(s)! //  ! で nil を無視して Double? を Double に変換

無限大( .infinity )と NaN ( .nan

Double.infinity  // +Inf
-Double.infinity // -Inf
Double.nan       // NaN

NaN のチェックには isNaN プロパティを用います。

// NaN のチェック
if a.isNaN {
    ...
}

π( .pi )と e ( M_E

Double.pi // 3.1415926535897931

Swift 5.3 現在 Double.e はないので、 libc の M_E を↓のようにして利用します。

import Foundation
M_E // 2.7182818284590451

浮動小数点数リテラル( 42.0

let a = 42.0
let b = 4.2e1 // これも 42.0

DoubleFloatExpressibleByIntegerLiteral プロトコルに適合しているので、浮動小数点数リテラルの他に整数リテラルを用いることもできます。

let a: Double = 42 // ✅ OK

ただし、暗黙の型変換ではないので↓はできません。

let a = 42        // a は Int 型
let b: Double = a // ⛔ コンパイルエラー

真偽値( Bool

let a: Bool = true
let b: Bool = false

toggle メソッドで値を反転させることができます。

// toggle メソッドによる Bool 値の反転
var f = true
f.toggle()
print(f) // false

toggle メソッドを利用するためにはその真偽値が可変であること( var に代入されているなど)が必要です。

文字列( String

let s: String = "abc"

文字列の文字数( count, isEmpty

"abc".count // 3

Swift では次のような絵文字も 1 文字としてカウントできます。

"👨‍👩‍👧‍👦".count // 1

空文字列かどうかは isEmpty で確認できます。

"abc".isEmpty // false
"".isEmpty    // true

文字列の分割( split

"A B C".split(separator: " ") // ["A", "B", "C"]

競プロでは入力文字列を分割して整数に変換することが多いと思いますが、次のように書けます。

"2 3 5".split(separator: " ").map { Int($0)! } // [2, 3, 5]

文字列の結合( joined

let ss: [String] = ["A", "B", "C"]
ss.joined(separator: " ") // "A B C"

IntArray[Int] )を結合する場合などは次のように書けます。

let numbers: [Int] = [2, 3, 5]
numbers.map(String.init).joined(separator: " ") // "2 3 5"

文字列のフォーマット( "String(format:_:)" )

C 形式のフォーマットが可能です。

let y = 2020
let m = 10
let d = 24
let s = String(format: "%04d-%02d-%02d", y, m, d)
print(s) // 2020-10-24

文字列型への変換

// Int → String の変換
let a: Int = 42
let s: String = String(a) 

また、 CustomStringConvertible に適合した型であれば description プロパティで String に変換することもできます。

// Int → String の変換( description の利用)
let a: Int = 42
let s: String = a.description

さらに、すべての式は文字列補間を使って文字列リテラルに埋め込めます。

// Int → String の変換(文字列補間の利用)
let a: Int = 42
let s: String = "\(a)"

文字列リテラル( "abc"

let s = "abc"

""" を使って複数行の文字列リテラルを書くこともできます。

// 複数行の文字列リテラル( " も使える)
let s = """
<ul id="foo">
    <li>Python</li>
    <li>JavaScript</li>
    <li>Swift</li>
</ul>
"""

文字列補間( "\(a)"

\() を使って文字列リテラルに式を埋め込めます。

print("2 + 3 = \(2 + 3)") // 2 + 3 = 5

競プロにおいては、実行結果として複数値を出力しなければならない場合などに便利です。

// スペース区切りで a, b, c の値を出力
print("\(a) \(b) \(c)")

コレクションとしての文字列

Swift の StringCharacter (文字)のコレクションです。 Array などと同じく for-in 文でイテレーションできます。

// 文字列とイテレーション
let s = "abc"
for c in s {
    print(c)
}
a
b
c

ただし、インデックスを指定して文字にランダムアクセスすることはできません(絵文字の文字数を上手く数えられることから推測できるように Character のサイズは固定でないので、 i 文字目のアドレスを知るには前からトラバースしなければならないため)。繰り返しランダムアクセスが必要な場合は一度 Array に変換するのが良いでしょう。

// 文字列中の文字へのランダムアクセス
let s: String = "abcdefg"
let cs: [Character] = Array(s)
print(cs[2]) // c

部分文字列( Substring

let s: Substring = "abcdefg".dropFirst(3) // "defg"

Swift では部分文字列型 SubstringString と型として区別されます。 String に変換する必要がある場合は↓のようにします。

let a: Substring = "abcdefg".prefix(3) // "abc" ( Substring )
let s: String = String(a)              // "abc" ( String )

なぜ StringSubstring の型が分かれているかについてはこちら

文字( Character

let c: Character = "a"

StringCharacter のコレクションなので、 String の要素は Character です。

// String の最初の要素を取得
let c: Character = "abc".first! // "a"

↑で ! が必要なのは nil が返される可能性があるからです。空文字列の場合 first で最初の文字を取得することができないため nil が返されます。そのため、 first の戻り値の型は Character?Optional<Character> )です。空文字列でないことがわかっている場合、 !nil を無視し、 Character?Character に変換できます。

文字リテラル( "a"

let c: Character = "a"

文字列リテラルと同じに見えますが、これは文字(正確には書記素クラスタ)リテラルです。詳細はこちら

配列( Array

let a: [Int] = [2, 3, 5]
print(a[0]) // 2

配列の型( [Int], Array<Int> など)

[Int]Array<Int> のシンタックスシュガーです。↓の二つはまったく同じ意味です。

let a: [Int] = [2, 3, 5]
let a: Array<Int> = [2, 3, 5]

通常は [Int] の形式が用いられることが多いです。

配列の要素数( count, isEmpty

[2, 3, 5].count // 3
[2, 3, 5].isEmpty // false
[].isEmpty        // true

配列の変更

Swift の Arrayclass ではなく struct なことに注意が必要です。そのため、 let (定数)ではなく var (変数)に格納されてないと変更することができません。

// let だと Array を変更できない
let a: [Int] = [2, 3, 5]
a[2] = 4 // ⛔ コンパイルエラー
// var だと Array を変更できる
var a: [Int] = [2, 3, 5]
a[2] = 4 // ✅ OK

また、 struct のインスタンスは代入時にコピーされ共有されることがないため、 Array の代入後に一方を変更してももう一方には影響を与えません。

// Array の一方を変更してももう一方に影響はない
var a: [Int] = [2, 3, 5]
var b: [Int] = a
a[2] = 4
print(b[2]) // 5

代入時に毎回コピーされるとパフォーマンスに悪影響を与えそうですが、 Copy-on-Write という仕組みを使い、パフォーマンスへの影響を回避しています。代入時にはバッファをコピーせず共有して、実際に必要になるまでコピーを行いません。

// Copy-on-Write の例(コピーが発生する場合)
var a: [Int] = [2, 3, 5]
var b: [Int] = a // ここではコピーされない
a.append(7)      // バッファが共有されているので変更前にコピーされる
// Copy-on-Write の例(コピーが発生しない場合)
var a: [Int] = [2, 3, 5]
a.append(7)      // バッファが共有されていないので変更前のコピーは不要

配列への要素の追加( append, insert

// 末尾への要素の追加
var a = [2, 3, 5]
a.append(7)
print(a) // [2, 3, 5, 7]
// 末尾以外への要素の追加
var a = [1, 1, 2, 3, 5]
a.insert(0, at: 0)
print(a) // [0, 1, 1, 2, 3, 5]

appendO(1)insertO(n) です。

配列からの要素の削除( removeLast, remove, popLast

// 末尾からの要素の削除
var a = [2, 3, 5]
let r: Int = a.removeLast()
print(a) // [2, 3]
print(r) // 5
// 末尾以外からの要素の削除
var a = [0, 1, 1, 2, 3, 5]
let r: Int = a.remove(at: 0)
print(a) // [1, 1, 2, 3, 5]
print(r) // 0

空の Array に対して removeLast を呼び出すと実行時エラーになりますが、 popLast の場合は nil を返します。そのため、 popLast の戻り値の型は Optional です(要素の型が Int なら Int? )。

// 末尾からの要素の削除
var a = [2, 3, 5]
let r: Int? = a.popLast()
print(a) // [2, 3]
print(r) // Optional(5)

これを利用して、 popLast を使えば要素がなくなるまでループすることなどが可能です。

// 配列の要素がなくなるまでループ
var a = [2, 3, 5]
while let x = a.popLast() {
    print(x)
}
5
3
2

removeLast および popLastO(1)removeO(n) です。

配列のイテレーション

let a: [Int] = [2, 3, 5]
for x in a {
    print(x)
}
2
3
5

配列のネスト

let a: [[Int]] = [
    [2, 3],
    [5, 7, 11],
]

print(a[0][1]) // 3

配列リテラル

let a = [2, 3, 5]
let b: [Int] = [] // 空の配列リテラル、型推論できないので型の記述が必須

配列リテラル自体は型を持たないので、必ずしも Array を表すとは限りません。 ExpressibleByArrayLiteral プロトコルに適合した型であれば何でも配列リテラルで表すことができます。 Array の他に ArraySliceSet なども ExpressibleByArrayLiteral に適合しています。

// Array 以外の型を配列リテラルで表す
let a: ArraySlice<Int> = [2, 3, 5]
let b: Set<Int> = [2, 3, 5]

これは暗黙の型変換ではありません。左辺の型からリテラルの型が決定されています。

部分配列( ArraySlice

let a: [Int] = [0, 1, 1, 2, 3, 5]
let b: ArraySlice<Int> = a[1 ..< 4]
print(b) // [1, 1, 2]

a[start ..< end] のようにすると end は含まれず、 a[start ... end] のようにすると end も含まれます。また、 a[start...]a[..<end] のように、 startend の片方だけを指定することもできます(この start ..< end などは特殊な構文ではなく、すべて Range とその亜種です)。

array[start ..< end]ArraySlice を取得する処理は O(1) です。

Swift では部分配列型 ArraySliceArray と型として区別されます。 Array に変換する必要がある場合は↓のようにします。

let a: [Int] = [0, 1, 1, 2, 3, 5]
let b: ArraySlice<Int> = a[1 ..< 4] // [1, 1, 2] ( ArraySlice<Int> )
let c: [Int] = Array(b)             // [1, 1, 2] ( [Int] )

Array(arraySlice)Array を生成する処理は O(n) です。

なぜ ArrayArraySlice の型が分かれているかについてはこちら

辞書(連想配列)( Dictionary

let a: [String: Int] = ["x": 2, "y": 3, "z": 5]
print(a["x"])  // Optional(2)
print(a["x"]!) // 2

ハッシュテーブルで実装されているため、基本的な操作は O(1) です。

Array と違い、 Dictionary をキーで引く場合、キーに対応した値が登録されていないと nil が返されます。そのため、 a["x"] の戻り値の型は Int ではなく Int?Optional<Int> )になります。キーに対応した値が存在することがわかっている場合は a["x"]! のように ! を付けることで nil を無視し、(このケースであれば) Int?Int に変換することができます。

辞書の型( [String: Int], Dictionary<String, Int> など)

[String: Int]Dictionary<String, Int> のシンタックスシュガーです。↓の二つはまったく同じ意味です。

let a: [String: Int] = ["x": 2, "y": 3, "z": 5]
let a: Dictionary<String, Int> = ["x": 2, "y": 3, "z": 5]

通常は [String: Int] の形式が用いられることが多いです。

辞書のエントリー数( count, isEmpty

["x": 2, "y": 3, "z": 5].count // 3
["x": 2, "y": 3, "z": 5].isEmpty // false
[:].isEmpty                      // true

count および isEmptyO(1) です。

辞書の変更

DictionaryArray と同じく struct で値型です。変更するためには let (定数)ではなく var (変数)に格納されている必要があります。

// let だと Dictionary を変更できない
let a: [String: Int] = ["x": 2, "y": 3, "z": 5]
a["w"] = 7 // ⛔ コンパイルエラー
// var だと Dictionary を変更できる
var a: [String: Int] = ["x": 2, "y": 3, "z": 5]
a["w"] = 7 // ✅ OK

Copy-on-Write についても Array と同様です。

値の変更・追加は O(1) です。

辞書のエントリーの削除

var a: [String: Int] = ["x": 2, "y": 3, "z": 5]
a.removeValue(forKey: "z")
print(a) // ["x": 2, "y":, 3] (順不同)

removeValueO(1) です。

辞書のイテレーション

let a: [String: Int] = ["x": 2, "y": 3, "z": 5]
for (key, value) in a {
    print("\(key) -> \(value)")
}
x -> 2
y -> 3
z -> 5

(順不同)

辞書のキーの存在確認( keys.contains

["x": 2, "y": 3, "z": 5].keys.contains("x") // true
["x": 2, "y": 3, "z": 5].keys.contains("w") // false

keys.containsO(1) です。

辞書リテラル( ["x": 2, "y": 3], [:] など)

let a = ["x": 2, "y": 3, "z": 5]
let b: [String: Int] = [:] // 空の辞書リテラル、型推論できないので型の記述が必須

集合( Set

let a: Set<Int> = [2, 3, 5]
print(a.contains(3)) // true
print(a.contains(4)) // false

イテレーションや要素数の取得など、基本的に Array と同じです。

ハッシュテーブルで実装されているため、基本的な操作は O(1) です。

集合への要素の追加( insert

var a: Set<Int> = [2, 3, 5]
a.insert(7)
print(a) // [2, 3, 5, 7] (順不同)

insertO(1) です。

集合からの要素の削除( remove

var a: Set<Int> = [2, 3, 5]
a.remove(5)
print(a) // [2, 3] (順不同)

removeO(1) です。

レンジ( Range, ClosedRange など)

let a: Range<Int>       = 0 ..< 100 // 100 を含まない
let b: ClosedRange<Int> = 0 ... 100 // 100 を含む

その他にも、上界・下界だけを定めたレンジを作ることもできます。

let c: PartialRangeUpTo<Int>    = ..<100
let d: PartialRangeThrough<Int> = ...100
let e: PartialRangeFrom<Int>    = 100...

レンジの生成は O(1) です。

レンジに含まれるか( contains

let a: Range<Int> = 0 ..< 100
print(a.contains(0))   // true
print(a.contains(50))  // true
print(a.contains(100)) // false

レンジのイテレーション

for i in 1 ... 3 {
    print(i)
}
1
2
3

Comparable に適合した任意の型について Range を作ることができますが、 Range<String> などはイテレートすることができません。イテレートできるのは RangeBoundRange<Int> なら Int )が Strideable プロトコルに適合し、かつ Bound.StrideSignedInteger プロトコルに適合する場合だけです。

タプル( (Int, String) など)

let t: (Int, String) = (42, "abc")
print(t.0) // 42
print(t.1) // abc

Swift のタプルはコレクションではないのでイテレートすることはできません( IntString など型を混ぜられるのでイテレートできるのは不自然です)。

Swift のタプルは値型であり、値変数はスタック領域に確保されるので、タプルを使っても(オブジェクトに包まれるなどの)オーバーヘッドがありません。

タプルの分解

let t = (42, "abc")
let (a, b) = t
print(a) // 42
print(b) // abc

ラベル付きタプル

let p: (x: Double, y: Double) = (2.0, 3.0)
print(p.x) // 2.0
print(p.y) // 3.0

または型推論を用いて↓のようにも書けます。

let p = (x: 2.0, y: 3.0)
print(p.x) // 2.0
print(p.y) // 3.0

空のタプル

空のタプルの型は () です。 Void は空のタプルの型 () のエイリアスです。↓の二つは全く同じ意味になります。

let a: Void = ()
let a: () = ()

1 要素のタプル

Int などの普通の型はすべて 1 要素のタプル (Int) などと等価です。

let a: (Int) = 42 // ✅ OK
let b: Int = a    // ✅ OK

オプショナル( Optional

Swift では普通の型に nilnull 相当のもの)を代入することはできません。 nil を代入したい場合は Optional 型にします。

let a: Int = nil // ⛔ コンパイルエラー
let a: Int? = nil // ✅ OK

Int?Int または nil を表す型なので、そのままでは Int のように使うことはできません。

let a: Int? = 2
print(a + 1) // ⛔ コンパイルエラー

↑の例では aInt ではなく Int? 型なので a + 1 ができません。

オプショナルの型( Int?, Optional<Int> など)

Int?Optional<Int> のシンタックスシュガーです。↓の二つはまったく同じ意味になります。

let a: Int? = nil
let a: Optional<Int> = nil

通常は Int? の形式が用いられます。

非オプショナル型への変換( if let など )

Int?Int として使うためには anil でないことをチェックする必要があります。

let a: Int? = 2
if let a = a { // a が nil でなかったときだけ新しい定数 a を作って代入
    print(a + 1) // ✅ OK
}

この if let a = a のような代入を Optional Binding といい、新しい a の型は Int になります。この新しい aif 文の範囲でのみ有効です。

Optional Binding の右辺には式を書くこともできます。そのため、次のようなコードを書く機会は多いです。

if let a = array.first {
    // array が空でない場合の処理
}

if 以外に guardwhile でも Optional Binding が使えます。

非オプショナル型への変換( !

もしオプショナル型が nil でないことがわかっている場合には ! 演算子を使って強制的に非オプショナル型に変換( Forced Unwrapping )することができます。

let a: Int? = 2
print(a! + 1) // 3

Forced Unwrapping は適切に使えば役に立ちますが、非オプショナル型への変換と分岐を同時にしたい場合には Optional Binding を使いましょう。

// 👎 Swift に不慣れな人の書いたコード
if !array.isEmpty {
    let a = array.first!
    print(a + 1)
}
// 👍 Swifty なコード
if let a = array.first {
    print(a + 1)
}

nil の代替値( ??

let a: Int = array.first ?? 0

a ?? banil だった場合に b を返します。 a の型が Foo? だった場合、 ba ?? b の型は Foo です。

制御構文

条件分岐

if

if a < 42 {
    print("真")
}
if a < 42 {
    print("真")
} else {
    print("偽")
}
if a < 42 {
    print("小")
} else if a > 42 {
    print("大")
} else {
    print("等")
}

if の後ろの条件式に () は不要です。 {} は必須です。ただし、条件式に Trailing Closure を書く場合はパースの問題で () が必要です。

// 条件式に () が必要な場合
if (array.reduce(true) { $0 && $1 > 0 }) {
    // ...
}

switch

switch a {
case 0:
    print("零")
case 1:
    print("壱")
case 2:
    print("弐")
case 3:
    print("参")
default:
    print("他")
}

case ごとの break は不要です。ただし、 case の後に書くコードが空の場合は break を書きます。 C や Java のように( break せず) fallthrough したい場合には fallthrough を書きます。

Swift の switch は網羅的な分岐が必須なので、↑の例では default が必要です。 default がないとコンパイルエラーになります。

パターンマッチング

switch を使ってパターンマッチングすることもできます。

let a: Bool = true
let b: Bool = false
switch (a, b) {
case (true, true):
    print("真真")
case (true, false):
    print("真偽")
case (false, true):
    print("偽真")
case (false, false):
    print("真真")
}

↑のように分岐が網羅的な場合には default は不要です。

guard

guard は満たすべき条件を記述し、条件を満たさないケースで早期脱出( return, break など)させるためのものです。

guard score >= 60 else {
    return // 早期脱出
}
// score >= を満たす場合の処理

Optional Binding と組合せて利用するケースも多いです。

// guard let
guard let first = array.first else {
    return // 早期脱出
}
// first を使う処理

ループ

while

var a = 10
while a >= 0 {
    print(a)
    a -= 1
}

Optional Binding と組合せて利用するケースも多いです。

// while let
var a = [2, 3, 5]
while let x = a.popLast() {
    print(x)
}
5
3
2

repeat-while

多くの言語で do-while と呼ばれるものです。 Swift では do は無名スコープに用いられるので、代わりに repeat-while になっています。

var a = 0
repeat {
    print(a)
    a += 1
} while a < 10

for-in

let a = [2, 3, 5]
for x in a {
    print(x)
}

Swift には for (int i = 0; i < n; i ++) 形式の for はありません。そのようなケースでは for とレンジを組合せます。

// 0 から 10 までのループ( 10 は含まず)
for i in 0 ..< 10 {
    print(i)
}

for (int i = 0; i < n; i += 2) のようにステップを設定したい場合は stride 関数を使います。

// ステップ 2 のループ
for i in stride(from: 0, to: 10, by: 2) {
    print(i)
}

無名スコープ

クロージャ式と区別するため、 { } ではなく do { } が用いられます。

let a = 2
print(a) // 2
do {
    print(a) // 2
    let a = 3
    print(a) // 3
}
print(a) // 2

関数

func square(of number: Int) -> Int {
    number * number
}

square が関数名、 of がラベル、 number が引数名、その直後の : Int が引数の型、最後の -> の右の Int が戻り値の型を表します。

この関数は↓のように呼び出せます。 of: がラベルとして現れていることに注意して下さい。

square(of: 3) // 9

ラベルと引数名が同じ場合には一つにまとめることができます。

// ラベルと引数名が同じ場合
func triangleAreaWith(base: Double, height: Double) -> Double {
    base * height / 2
}

↑は↓と同じ意味です。

// ラベルと引数名を別々に書いた場合
func triangleAreaWith(base base: Double, height height: Double) -> Double {
    base * height / 2
}

ラベルが不要な場合には _ を書きます。

// ラベルが不要な場合
func tan(_ x: Double) -> Double {
    sin(x) / cos(x)
}

関数の { } の中が単一の式でない場合には return が必要です。

// { } の中が単一の式でないので return が必要
func sum(of array: [Int]) -> Int {
    var sum = 0
    for element in array {
            sum += element
    }
    return sum // return が必須
}

関数の型パラメータ

// 型パラメータ T を使って恒等関数 id を実装
func id<T>(_ value: T) -> T {
    value
}

型パラメータに制約を付けることもできます。↓は型パラメータ TAdditiveArithmetic プロトコルに適合しているという制約を付けています。

func sum<T>(of array: [T]) -> T where T: AdditiveArithmetic {
    var sum = T.zero
    for element in array {
            sum += element
    }
    return sum
}

制約のおかげで T.zerosum += element における T 同士のたし算を記述できます。

関数の型

(第 1 引数の型, 第 2 引数の型, ...) -> 戻り値の型 で関数の型を表します。

func triangleAreaWith(base: Double, height: Double) -> Double {
    base * height / 2
}

// f は (Double, Double) -> Double 型
let f: (Double, Double) -> Double = triangleAreaWith(base:height:)
f(10, 4) // 20

クロージャ式(ラムダ式)

多くの言語でラムダ式と呼ばれるものを Swift ではクロージャ式と呼びます。

let f: (Double, Double) -> Double = { base, height in
    base * height / 2
}

クロージャ式の引数名を省略することもできます。その場合、順番に $0, $1, ... が割り振られます。

let f: (Double, Double) -> Double = {
    $0 * $1 / 2
}

高階関数

let a = [1, -2, 3]
a.map(abs) // [1, 2, 3]

Swift の演算子は関数なので高階関数に渡すこともできます。

// 演算子を関数として高階関数に渡す
[2, 3, 5].reduce(0, +) // 10 ( [2, 3, 5] の合計 )

クロージャ式を直接渡すこともできます。

// 高階関数にクロージャ式を渡す
let a = [2, 3, 5]
a.map({ $0 * $0 }) // [4, 9, 25]

最後の引数がクロージャ式の場合、クロージャ式を関数の () の外側に出すことができます。これを Trailing Closure と呼びます。

// Trailing Closure
let a = [2, 3, 5]
a.map() { $0 * $0 } // [4, 9, 25]

さらに、 Trailing Closure にした場合、 () の中が空だと () を省略することができます。

// () の省略
let a = [2, 3, 5]
a.map { $0 * $0 } // [4, 9, 25]

標準ライブラリの高階関数

[2, 3, 5].map { $0 * $0 } // [4, 9, 25]
[0, 1, 1, 2, 3, 5].filter { $0.isMultiple(of: 2) } // [0, 2]
(1 ... 100).reduce(0, +) // 5050
[[2], [3, 5], [7, 11, 13]].flatMap { $0 } // [2, 3, 5, 7, 11, 13]
["2", "3", "four", "5", "six", "7"].compactMap { Int($0) } // [2, 3, 5, 7]
[2, 3, 5, 7, 11, 13].prefix(while: { $0 < 10 }) // [2, 3, 5, 7]
[2, 3, 5, 7, 11, 13].drop(while: { $0 < 10 }) // [11, 13]
[3, 2, 4, 5, 1].sorted(by: >) // [5, 4, 3, 2, 1]

inout 引数

inout 引数によって参照渡し(のようなこと)ができます。 inout 引数には関数の中から結果を書き込むことができ、それが呼び出し元に反映されます。

func swap<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

inout 引数に値を渡すときには & を付けます。 inout 引数に渡せるのは左辺値( l-value )のみです。

var x = 2
var y = 3
swap(&x, &y)

print(x) // 3
print(y) // 2

標準入出力

標準入力

// 単一行を読み込み
let line: String = readLine()!

readLine はこれ以上読み込める行がない場合 nil を返します。そのため、 readLine の戻り値の型は String?Optional<String> )です。 nil にならないことがわかっているなら !nil を無視し、 String?String に変換します。

↓のような入力を [Int] に変換したい場合、

2 3 5

map 等と組み合わせて次のように書けます。

let a: [Int] = readLine()!.split(separator: " ").map { Int($0)! }

標準出力

print(42)

print はデフォルトで出力後改行します。改行が不要の場合は terminator"" を渡します。

print("A", terminator: "")
print("B", terminator: "")
print("C")
ABC

Discussion

T.Muta a.k.a 417.72KIT.Muta a.k.a 417.72KI

論理演算子の項ですが、短絡評価で isFoo を実行させないのなら && ではなく || ではないかと思うのですがいかがでしょうか?

ひろんひろん

標準入力を [Int] に変換したい場合ですが、 .split(separator: " ") が抜けていると思います。

Yuta KoshizawaYuta Koshizawa

ご指摘ありがとうございます!修正しました。一応投稿前に全コード動作確認したんですが抜け落ちていたようです💦