Swift
メインページ > 工学 > 情報技術 > プログラミング > Swift
Swiftは、Appleが、iOS、iPadOS、macOS、tvOS、および watchOS のために開発したオープンソースのプログラミング言語です。
目次[編集]
- Swift/
- Swift/文法 - 主に制御構造、関数定義について
- Swift/オブジェクト指向 - 主に列挙体、クラス、構造体について
- Swift/非同期処理 - 主にGrand Central Dispatchによる非同期処理について
環境準備[編集]
オンラインコンパイル実行[編集]
ローカルにコンパイル実行環境を作るのが困難、すぐにコンパイルと実行を試してみたい。そんな場合には、オンラインコンパイル実行環境を使うことも検討に値します。
- Swift Playgrounds
- 公式のオンラインコンパイル実行環境です。
- paiza.io
- 複数のプログラミン言語に対応しており、Swiftにも対応しています。
ビルド済みバイナリーの導入[編集]
公式サイトの、Download Swiftからインストーラーを入手するのが基本です。
- iPadOS
- Appleから、「Swift Playgrounds」が学生を対象に公開されています。
- Swift Playgroundsは開発環境であるとともに、Swiftの基本を習得するためのチュートリアルを含んでいます。
- macOS
- Swiftを開発したAppleのプラットフォームです。
- macOS 10.9 以降をサポートしています。
- Xcodeに統合されています。
- 複数のツールチェインがSwiftをサポートしているので、目的に応じて切り替えて使用します。
- Windows
- Windows10以降をサポートしています(Windows8.1以前はサポート対象外)。
- GNU/Linuxのディストリビューション
- GNU/Linuxのディストリビューションの場合、公式にサポートされているディストリビューションと公式にはサポートされず独自にパッケージを用意していディストリビューションがあります。
公式にサポートされているディストリビューション[編集]
公式サイトの、Download SwiftからTARBALLをダウンロードしてインストールします。
- Ubuntu
- 18.04 以降をサポートしています。
- CentOS
- 7 以降をサポートしています。
- Amazon Linux
- 2 以降をサポートしています。
公式にサポートされていないディストリビューション[編集]
パッケージマネージャによってパッケージ名と依存関係、インストールに使用するコマンドが異なります。
公式では、RPMでも提供されていますが experimental use only との位置づけです
- Fedoraの場合
- Fedora 独自のパッケージリポジトリーから非公式版をインストールします。
- 最新の利用可能なバージョンへインストール済みパッケージを同期する
$ sudo dnf distro-sync
- インストール
$ sudo dnf install swift-lang
ソースコードからのビルド[編集]
最新のあるいはリリース前のバージョンのSwiftをインストールしたい場合は、ソースコードを入手しビルドします。
- ソースコードの入手
- https://github.com/apple/swift から clone します。
- ビルド環境の構築
- ビルド環境の構築のために build-toolchain スクリプトが用意されています。--help で全てのオプションの説明を見ることが出来ます。
- コンフィギュレーション
- ビルド
- テスト
- インストール
実行方法[編集]
Hello World[編集]
コードは
- hello.swift
print( "Hello, World!" )
の1行です。これをテキストエディターでコードを書き、ファイル名 hello.swift
保存します。swiftのソースファイルの拡張子には .swift
が使われます。
コンパイルする場合[編集]
実行方法は、まずコンパイルのために
swiftc ファイル名.swift
を実行します。
すると、標準設定ならカレントディレクトリなどシステム標準の場所に ファイル名 の実行ファイルが出来るので、あとはそれを通常の実行ファイルと同じ方法で実行します。
MS-DOSやWindowsでは、PATHが通っていなくてもカレントフォルダのファイルを名前を打つだけで実行できますが、他のプラットフォームの場合は
./ファイル名
のようなに ./
を前置してカレントディレクトのファイルであることを明示して実行します。
インタプリタの場合[編集]
コマンド
swift ファイル名.swift
で、インタプリタとしてコンパイル無しで実行できます。
かつて「swift run」というコマンドだったが、現代では廃止され、上記のようなコマンドになっています。
対話モードの場合[編集]
コマンド
swift
で対話モードになります。
終了したい場合、Ctrl + D ボタンで終了します。
定数と変数[編集]
変数[編集]
変数は、値と結びついた識別子で初期化や代入によって結びつく値を変えることが出来ます。
変数は、キーワード var
を使って宣言します。
- 変数の宣言
var 変数名: 型 = 式
定数[編集]
定数は、一度しか値をアサインできない変数です。
定数は、キーワード let
を使って宣言します。
- 定数の宣言
let 定数名: 型 = 式
- 変数の値を参照
var a: Int = 47 print( a )
- 実行結果
47
型 Int
は冒頭が大文字でなければなりません。Swiftでは大文字と小文字は異なる文字です。
識別子[編集]
定数や変数の名前のことを識別子( identifier )と言います(他にも関数・メソッド・クラス・クラスのメンバーなどの名前も識別子で、同じ名前空間の中では識別子は重複できません)。
- 識別子には以下の文字セットが使えます。
- 英数字(a-z, A-Z, 0-9)
- アンダースコア(_)
- $ 記号
- Unicode文字
- 識別子の先頭に数字(0-9)を使うことは出来ません。
var
のようなSwiftのキーワードは識別子に使用できません。print
のような標準ライブラリー関数は識別子に使用すべきではありません。
この規則に違反したコードはコンパイルエラーになります。
- 標準ライブラリー関数の名前を定数の名前に使った
let print = 0 print(print)
- コンパイル結果
main.swift:2:1: error: cannot call value of non-function type 'Int' print(print)
ただし、識別子を `(バッククオーテーション)で括るとキーワードも識別子に使うことができます。
- `(バッククオーテーション)で括りキーワードを識別子に使う
let `var` = 42 print(`var`)
- 実行結果
42
初期化と参照[編集]
- 定数と変数は宣言時の初期化を省略できます
var a: Int a = 31 print( a ) var b: Int b = 42 print( b )
- 実行結果
31 42
定数と変数は宣言時に初期化を省略できますが、初期化を省略した変数の値を参照するとコンパイル時にエラーになります。
- 宣言時に初期化を省略した変数の値を参照(コンパイル時にエラーになります)
var a: Int print( a )
- コンパイル結果
main.swift:2:8: error: variable 'a' used before being initialized print( a ) ^
型推論[編集]
初期値を伴って変数か定数が宣言された場合、型アノテーション(type annotation; : 型名
の部分)を省略することができます。
これを型推論( type inference )と呼びます。
- 型推論
let a = 31 print( a, String(describing: type(of: a)) ) let b = "abc" print( b, String(describing: type(of: b)) ) let c = 3.1415926536 print( c, String(describing: type(of: c)) )
- 実行結果
31 Int abc String 3.1415926536 Double
String(describing: type(of: 式)
は、式の型を文字列で返します。
一般に定数と変数は宣言に初期化することは良い習慣だと考えられています。このため、多くのシチュエーションで型推定が可能となり型アノテーションが省略できます。
型アノテーションを省略すると、『コードの意図が読みにくくなる』とコードレビューで指摘されることがありますが、全部の宣言に型アノテーションを追加すると、『型アノテーションが冗長』とコードレビュー指摘されます。「どのような場合に、型アノテーションを書くべきか」一般則はありませんが let str = "abc"
に型アノテーションを書くべきだと主張する人はまれなので、定数と変数の名前えらびは重要で、単に a や b の様な「色のない」 名前は選ぶべきではありません。
暗黙の型変換は行われない[編集]
なお、いかなる数値型の変数についても暗黙の型変換( implicit conversion )が行われることはなく、型の違う数値同士の演算、右辺と左辺で型の異なる代入は全てコンパイルエラーとなります。
- 符号の有無の違う定数による初期化
let signed: Int = 1 let unsigned: UInt = signed
- コンパイル結果
main.swift:2:22: error: cannot convert value of type 'Int' to specified type 'UInt' let unsigned: UInt = signed ^~~~~~ UInt( )
- 数値リテラル
1
は、UIntの範囲内ですが swift は型の不整合を理由にエラーにします。
- 型の異なる定数と数値リテラルからなる式
let signed: Int = 1 let number = signed + 1.0
- コンパイル結果
main.swift:2:8: error: binary operator '+' cannot be applied to operands of type 'Int' and 'Double' signed + 1.0 ~~~~~~ ^ ~~~ main.swift:2:8: note: overloads for '+' exist with these partially matching parameter lists: (Double, Double), (Int, Int) signed + 1.0 ^
- 型の異なる数値リテラル同士からなる式
let number = 1 + 1.0 print( number, String(describing: type(of: number)) )
- 実行結果
2.0 Double
- これは暗黙の型変換に似ていますが、数値リテラルのみからなる式(=コンパイル時定数式)で、コンパイル時に静的に評価されます。
- Double.piは数値リテラル扱い?
let rad_to_deg_factor = Double.pi / 180 print( rad_to_deg_factor, String(describing: type(of: rad_to_deg_factor)) )
- 実行結果
0.017453292519943295 Double
- なぜ?
基本データ型[編集]
数値[編集]
符号付き整数の型には、Int
、Int8
、Int16
、Int32
、Int64
があります。Int
は、32ビット環境ではInt32
と同じサイズ、64ビット環境ではInt64
と同じ。
符号無し整数の型には、UInt
、UInt8
、UInt16
、UInt32
、UInt64
があります。UInt
は、32ビット環境ではUInt32
と同じサイズ、64ビット環境ではUInt64
と同じ。
浮動小数点数の型には、IEEE 754 単精度Float
と、倍精度のDouble
があります。
先述の通り、上記の型に対して暗黙の型変換( implicit conversion )が行われることは一切ありません。
「int」など小文字だとエラーになります。冒頭は大文字でInt
のように書かなければなりません。
文字列[編集]
Swiftの文字列はString
型、文字はCharacter
型です。
- コード例
var a: String = "good morning" print(a)
- 実行結果
good morning
二重引用符 ( " から次の " まで)の中に、変数に代入したい文字または文字列を書く。変数のセクションではいちいち説明しなかったかもしれませんが、変数には数値だけでなく文字列や文字も代入できます。
文字や文字列を代入する場合、シングル引用符「'」だとエラーになります。二重引用符を使うこと。
文字列と別の文字列の連結は、+
演算子で行えます。
- コード例
let greet1 = "good" let greet2 = "afternoon" let msg = greet1 + " " + greet2 print(msg)
- 実行結果
good afternoon
表示したい文字列中に変数値を埋め込む場合、下記の方法のいずれかを使えばいいです。String()
でキャストする方法か、または\()
を使う方法です。
- コード例
// 方法1 var a = 14 var msg1 = "彼は" + String(a) + "歳" print(msg1) // 方法2 var b = 16 var msg2 = "彼女は\(b)歳" print(msg2)
- 実行結果
彼は14歳 彼女は16歳
UTF-16表現ではサロゲートペアを要する拡張領域の文字も1文字として扱う。
下記のように、オブジェクトの文字数をカウントするcountプロパティが用意されているので、それでカウントするとコメント(// より行末までが実行時には無視されます)にある結果が表示されます。
import Foundation let str = "aαあ𪚲" print(str.utf8.count) // 10 print(str.utf16.count) // 5 print((str as NSString).length) // 5 = length in UTF-16 print(str._bridgeToObjectiveC().length) // 5 let char = str.character(at:3) print(type(of: char)) // UInt16 print(String(format:"%x", char)) // d869
NSString の利用には Foundation のインポートが必要なので、上記コードではインポートしています。
配列[編集]
配列は、Array<型>
ないし[型]
と宣言します。より直感的な後者が推奨されています。
var arrayOfChars: [Character] // 宣言のみ var arrayOfInts = [Int]() // 空の配列として初期化
let fibs = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] // [Int] let transcendentals = [ 2.7182818284590451, 3.1415926535897931 ] // [Double] let falsies = [false, 0, 0.0, ""] // [Any] 型の混在
なお、[]
は空の配列リテラルであるが、要素の型を何らかの形で指定する必要がある
var ints: [Int] = [] var doubles: [Double] = [] var any: [Any] = [] var unknown = [] // 型推論ができないため、コンパイルエラー
配列の結合、代入
var ints1: ArraySlice<Int> = [10,20,30] var ints2: ArraySlice<Int> = [40,50] ints1 = ints1 + ints2 // [10,20,30,40,50] ints2[1] = 55 // [40,55] ints1[1...2] = ints2 // [10,40,55,40,50] ints1 = ints2 // [40,55]
空の定義を宣言した場合は、下記のように、あとで例えば.append
などで具体的な値とともに項を追加する必要があります。なお、値なしで配列領域だけ確保することは推奨されておらず、標準の方法ではエラーになります。
var ary = [Int](); ary.append(5) print(ary[0])
- 実行結果
5
- 基本操作
var arr = [0, 1, 2, 3, 4, 5, 6] arr.append(7) print(arr) // [0, 1, 2, 3, 4, 5, 6, 7] arr += [8, 9, 10] print(arr) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] arr.insert(11, at:2) print(arr) // [0, 1, 11, 2, 3, 4, 5, 6, 7, 8, 9, 10] arr[2] = 12 print(arr) // [0, 1, 12, 2, 3, 4, 5, 6, 7, 8, 9, 10] arr[2...2] = [11, 12, 13] print(arr) // [0, 1, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9, 10] arr.remove(at:0) print(arr) // [1, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9, 10] arr.removeLast() print(arr) // [1, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9] arr[5...] = [99] print(arr) // [1, 11, 12, 13, 2, 99] let index13 = arr.index(of: 13) print(index13) // Optional(3)
let squared = arr.map{ i in i * i } print(squared) // [1, 121, 144, 169, 4, 9801] let filtered = arr.filter{ n in n > 3 } print(filtered) // [11, 12, 13, 99] let sorted = arr.sorted{ (a, b) in a > b } print(sorted) // [99, 13, 12, 11, 2, 1] let sum = arr.reduce(0){ (s, n) in s + n } print(sum) // 138 arr.forEach{ n in print(n) } // 1↵121↵144↵169↵4↵9801
let arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] let arr1_1 = arr1.map{ a -> [Int] in a.reversed() } print(arr1_1) // [[3, 2, 1], [6, 5, 4], [9, 8, 7]] let arr1_2 = arr1.flatMap{ a -> [Int] in a.reversed() } print(arr1_2) // [3, 2, 1, 6, 5, 4, 9, 8, 7] let arr2 = [1, 2, nil, 4] let arr2_1 = arr2.map{ n -> Int? in n } print(arr2_1) // [Optional(1), Optional(2), nil, Optional(4)] let arr2_2 = arr2.flatMap{ n -> Int? in n } print(arr2_2) // [1, 2, 4]
セット[編集]
重複のないコレクション型
var set = [3, 1, 4, 1, 5, 9, 2, 6] as Set print(set)
基本操作
set.insert(5) print(set) // [1, 3, 4, 9, 6, 5, 2] set.remove(1) print(set) // [3, 4, 9, 6, 5, 2] print(set.contains(3)) // true var arr = set.sorted() print(arr) // [2, 3, 4, 5, 6, 9] var digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] as Set print(set.isSubset(of: digits)) // true
辞書[編集]
Swiftでは、連想配列は辞書(Dictionary)と呼ばれます。
辞書は総称型であり、キーの型KeyType
、値の型ValueType
を持つ辞書はDictionary<KeyType,ValueType>
または[KeyType: ValueType]
と宣言します。Array同様、より直感的な後者が推奨されています。
var name2num = [String:Int]() name2num["zero"] = 0 name2num["one"] = 1
let name2num = ["zero":0, "one":1, "two":2] // Dictionary<String, Int>
[:]
が空の辞書リテラルであるが、キーの型および値の型が指定されている必要がある点は配列と同様です。
var dict: [String: Int] = [:] var unknowndict = [:] // 型推論ができないため、コンパイルエラー
基本操作
var name2num = ["zero":0, "one":1, "two":2] name2num["three"] = 3 print(name2num) // ["two": 2, "one": 1, "three": 3, "zero": 0] name2num["zero"] = nil print(name2num) // ["two": 2, "one": 1, "three": 3] let one = name2num["one"] print(one) // Optional(1) print(name2num.keys) // ["two", "one", "three"] print(name2num.values) // [2, 1, 3] for element in name2num { print(element) // (key: "two", value: 2) ↵(key: "one", value: 1) ↵(key: "three", value: 3) } for (key, value) in name2num { print("\(key) = \(value)") // two = 2 ↵one = 1 ↵three = 3 } name2num.forEach{ (key, value) in print("\(key) = \(value)") // two = 2 ↵one = 1 ↵three = 3 }
タプル[編集]
let errorStatus: (Int, String) = (404, "Not Found")
let errorStatus = (404, "Not Found")
タプルの各要素には名前をつけることができます。名前付きタプルに対して、数値インデックスによって各要素にアクセスすることも可能。
let okStatus = (code: 200, message: "OK") print("\(okStatus.code): \(okStatus.message)") print("\(okStatus.0): \(okStatus.1)") // 200: OK // 200: OK
代入式で定数や変数に分解することができます。この際にアンダースコアを指定すると、その値を無視することができます。
let (_, message) = okStatus
オプショナル型[編集]
Swiftでは安全性のため、ある型の定数や変数にnil
を代入することは禁止されています。
変数にnil
を代入可能にするには、Optional
型でラップします。
オプショナル型の変数および定数は宣言のときに Optional<型名>
と書きます。
これには構文糖があり 型名?
あるい 型名!
と書くことも出来ます。
var n: Int = nil // コンパイルエラー var m: Int? = nil // オプショナル型はnilを代入可能 var l: Optional<Int> = nil // Int? は Optional<Int> の略記である
var o:Int! = nil // 暗黙的開示オプショナル型。自動的に強制アンラップされるが、nilの場合に実行時エラーとなる var p:ImplicitlyUnwrappedOptional<Int> = nil // Int! は ImplicitlyUnwrappedOptional<Int> の略記である
// 文字列の配列の中から指定した文字列を探す関数 func findString(data: [String], key: String) -> Int? { for index in 0..<data.count { if data[index] == key { return index } } return nil }
Optional<Type>
型の値からType
型の値を取り出すことを、アンラップするという。
アンラップ[編集]
オプショナル型の変数から基底型の値を取出すことをアンラップ( Unwrap )と呼びます。 アンラップには
- 強制アンラップ — オプショナル型の式から基底型の値を取出す。nilを渡すと実行時エラーが発生します。
- オプショナル束縛 — 条件式からペイロードをキャプチャーします。
- オプショナル連鎖 — メソッドやプロパティがnilを返すとチェインを中断します。
- nil結合演算子 — オプショナル型の式に nil だったときのディフォルトを与えます。
の4つの方法があります。
強制アンラップ[編集]
オプショナル型の式に !
をつけるとオプショナル型から基底型の値を参照できます。
これを強制アンラップ( Forced Unwrapping )と呼びます。
- オプショナル型の変数のアンラップ
var s: String? = nil print(s) s = "abc" print(s) print(s!)
- 実行結果
nil Optional("abc") abc
- 強制アンラップする前に nil でないことを確認する必要があります
let fruits = ["apple", "banana", "orange"] let possibleKiwiIndex = findString(data:fruits, key:"kiwi") // Int?型 if possibleKiwiIndex != nil { let kiwiIndex = possibleKiwiIndex! print("キウイは\(kiwiIndex)番目に見つかりました") } else { print("キウイは見つかりませんでした") }
- 強制アンラップを nil に適用すると実行時に破壊的なエラー(たいがいコアダンプ)を起こすので、次に示すオプショナル束縛・オプショナル連鎖やnil結合演算子も検討してください。
オプショナル束縛[編集]
if文とwhile文ではオプショナル束縛( optional binding )によりオプショナル型の式からペイロードをキャプチャーすることができます。
- オプショナル型の式からペイロードをキャプチャー
let fruits = ["apple", "banana", "orange"] if let kiwiIndex = find(fruits, "kiwi") { print("キウイは\(kiwiIndex)番目に見つかりました") } else { print("キウイは見つかりませんでした") }
オプショナル連鎖[編集]
オプショナル型の変数のメソッドやプロパティを呼び出す際には、オプショナル連鎖( Optional Chaining )を使うとオプショナル束縛を使うことなくメソッドチェインのように記述できます。
- オプショナル型のメソッドがnilでなければ次のメソッドを呼出す
var possibleOrangeIndex = findString(data:fruits, key:"orange") if possibleOrangeIndex?.distance(to:1).signum() == -1 { print("オレンジは2番目より後にあります") }
- オプショナル型のプロパティがnilでなければメソッドを呼出す
var path:String? = "/path/to/an/invisible/.file" var isInvisible = path?.split(separator:"/").last?.hasPrefix(".") print(isInvisible) // Optional(true)
演算子[編集]
算術演算子[編集]
文法 | 意味 |
---|---|
+ |
加算 |
- |
減算 |
* |
乗算 |
/ |
除算(整数型のゼロ除算はエラーとなります) |
% |
剰余(整数型のゼロでの剰余演算はエラーとなります) |
&+ |
加算(オーバーフローを無視します) |
&- |
減算(オーバーフローを無視します) |
&* |
乗算(オーバーフローを無視します) |
&/ |
除算(オーバーフローを無視し、ゼロ除算の結果は0 となります)(※廃止済み)
|
&% |
剰余(オーバーフローを無視し、ゼロでの剰余演算の結果は0 となります)(※廃止済み)
|
文法 | 意味 |
---|---|
+ |
単項プラス |
- |
単項マイナス(符号反転) |
++ |
インクリメント(式はインクリメントされた後の値を返す)※Swift 3.0で廃止[1] |
-- |
デクリメント(式はデクリメントされた後の値を返す)※Swift 3.0で廃止[1] |
文法 | 意味 |
---|---|
++ |
インクリメント(式はインクリメントされる前の値を返す)※Swift 3.0で廃止[1] |
-- |
デクリメント(式はデクリメントされる前の値を返す)※Swift 3.0で廃止[1] |
比較演算子[編集]
|
|
|
print(1...5 ~= 3) // true
var str = "mission control" print(str.range(of: "control")! ~= str.index(of: "c")!) // true
論理演算子[編集]
文法 | 意味 |
---|---|
&& |
論理AND |
|| |
論理OR |
! |
論理NOT |
三項演算子[編集]
文法 | 意味 |
---|---|
条件 ? 式1 : 式2 |
条件が真のとき式1の値を、偽のとき式2の値を返す |
nil結合演算子[編集]
文法 | 意味 |
---|---|
?? |
左オペランドにはT? 型、右オペランドにはT 型の値をとり、左オペランドに値が存在していればアンラップしてその値を返し、左オペランドが nil であれば右オペランドの値を返す
|
"x".toInt() ?? 0 // 0 "5".toInt() ?? 0 // 5
ビット演算子[編集]
文法 | 意味 |
---|---|
<< |
左シフト |
>> |
右シフト(左オペランドが符号付き整数の場合は算術シフト、符号無し整数の場合は論理シフト) |
& |
AND |
| |
OR |
^ |
XOR |
~ |
NOT(ビット反転) |
代入演算子[編集]
|
|
範囲演算子[編集]
文法 | 意味 |
---|---|
..< |
半分開いた範囲(終端を含まない):半開区間 |
... |
閉じた範囲(終端を含む):閉区間 |
キャスト演算子[編集]
文法 | 意味 |
---|---|
is |
型検査 |
as |
型キャスト |
as? |
オプショナル型へのキャスト キャストできない場合はnilとなる |
as! |
強制型キャスト キャストできない場合は実行時エラーとなる |
- キャスト演算子
var arr:[Any] = [1, 2.0, "3", -4] for item in arr { let intItem = item as? Int print(intItem) }
- 実行結果
Optional(1) nil nil Optional(-4)
import Foundation var array1 = [1, 2, 3, 4] as NSArray var mutableArray1 = array1 as? NSMutableArray // ダウンキャストできないので、nilになる // ※補足: 上記の例の場合、Mutableな状態で取得したければ array1.mutableCopy() を行うべき。 var mutableArray2 = [1, 2, 3, 4] as NSMutableArray var array2 = mutableArray2 as NSArray var mutableArray2_2 = array2 as? NSMutableArray // 元々mutableArray2の型はNSMutableArrayなので、キャストに成功する
その他[編集]
識別子にはUnicode文字を用いることができます。
let リンゴの数 = 3 let みかんの数 = 5
文字列リテラルの中にある\(...)
には、式の結果が展開される
let リンゴ説明 = "私は\(リンゴの数)個のリンゴを持っています。" // ”私は3個のリンゴを持っています。" let 果物説明 = "私は\(リンゴの数 + みかんの数)個の果物を持っています。" //"私は8個の果物を持っています。"
ヒアドキュメントには、ダブルクォーテーション3つを使用します。ヒアドキュメント内の行頭の空白は自動的にトリミングされます。
let tanka = """ 田子の浦に うち出でてみれば 白妙の 富士の高嶺に 雪は降りつつ """ print(tanka)
数値リテラルのプレフィックスは"0b
"で2進数、"0o
"で8進数、"0x
"で16進数を表す。
let dec = 29 let bin = 0b11101 // 2進数で29 let oct = 0o35 // 8進数で29 let hex = 0x1D // 16進数で29
浮動小数点リテラルは、通常の十進数表記に加え16進数表記もサポートしています。
let π = 3.1415926535897931 let pi = 0x1.921fb54442d18p+1 // NSString(format:"%a", π) の出力と同様
整数型と浮動小数点型のどちらでも、コードの見やすさのためにアンダースコア _ を桁の区切りとして挿入できます。
let threeHundledMillion = 300_000_000 let bitMask: UInt8 = 0b0010_0000
アンダースコアは、代入文で代入する値を無視したいときに、仮の代入先として使用できます。
var s:String? = "String" if let _ = s { print("sはnilではありません。") }
for _ in 0..<5 { print("repeat") }
let result = (404, "Not Found", false) let (_, message, _) = result
他言語との比較[編集]
C言語との類似点[編集]
- ほとんどのC言語の演算子はSwiftでも使用できます。
- ただし、Swiftではオーバーフローを伴う数値演算のサポートのための演算子が追加されています。
- 中括弧は、文をグループ化するために使用されます。
- 等号1つ
=
は代入、2つ==
は等価比較を意味します。- この他に、Swiftでは等号3つ
===
は同じオブジェクトを参照しているかどうかを確認するための演算子を意味します。
- この他に、Swiftでは等号3つ
while
、if
、for
等の制御文が類似しています。- ただし、Swiftでは拡張機能を有します。例えば、
while
、if
文はパターンマッチングや条件付きOptionalアンラップをサポートします。
- ただし、Swiftでは拡張機能を有します。例えば、
- 角括弧は、配列の宣言と配列の要素取得の両方で使用されます。
Objective-Cとの類似点[編集]
- 基本的な数値型
Int
、UInt
、Float
、Double
等のサポート。 - クラスメソッドは、インスタンスメソッドと同様に継承されます。クラスメソッド内の
self
は、メソッドが呼び出されたクラスを意味します。 for
...in
列挙構文のサポート。
Objective-Cとの相違点[編集]
- 文はセミコロン(
;
)で終わる必要はありません。しかし、1行に複数の文を記述する際に使用することができます。 - ヘッダーファイルが存在しません。
/*
~*/
によるコメントはネストできます。- 型推論のサポート。
- ジェネリックプログラミングのサポート。
- 関数は第一級オブジェクトです。
- 演算子はクラスに対して再定義(演算子のオーバーロード)でき、新しい演算子を定義できます。
- 文字列はUnicodeを完全にサポートします。ほとんどのUnicode文字は識別子や演算子でも使用できます。
- 例外処理は存在しません。Swift 2では例外処理とは互換性のない別のエラー処理モデルが導入されています。
- バグの原因となるC言語ファミリーの特徴がいくつか削除されています。
- デフォルトでは、ポインタは公開されていません。プログラマが参照の管理をする必要はありません。
- 変数割り当ては値を返しません。これにより、
=
と==
の誤用を防ぐことができます。 switch
文内でbreak
を行う必要はありません。明示的にfallthrough
を行わない限り次のcase
にフォールスルーすることはありません。- 変数と定数は常に初期化され、配列の境界は常にチェックされます。
- 算術オーバーフローは実行時エラーとしてトラップされます。オーバーフローを許可する演算子は
&+
、&-
、&*
、&/
、&%
として定義されます。また、全ての整数型にはプロパティmin
、max
が定義されており、潜在的なオーバーフローのチェックに利用することができます。 - ブロックを用いない1行の
if
文、while
文はサポートされていません。 - Off-by-oneエラーの原因となるC言語スタイルの
for (int i = 0; i < c; i++)
文は、Swift 3で削除されました。 - インクリメント演算子
++
、デクリメント演算子--
は、Swift 3で削除されました。