メインページ > 工学 > 情報技術 > プログラミング > Swift

Wikipedia
Wikipedia
ウィキペディアSwift (プログラミング言語)の記事があります。

Swiftは、Appleが、iOS、iPadOS、macOS、tvOS、および watchOS のために開発したオープンソースのプログラミング言語です。

目次編集

環境準備編集

オンラインコンパイル実行編集

ローカルにコンパイル実行環境を作るのが困難、すぐにコンパイルと実行を試してみたい。そんな場合には、オンラインコンパイル実行環境を使うことも検討に値します。

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をインストールしたい場合は、ソースコードを入手しビルドします。

  1. ソースコードの入手
    https://github.com/apple/swift から clone します。
  2. ビルド環境の構築
    ビルド環境の構築のために build-toolchain スクリプトが用意されています。--help で全てのオプションの説明を見ることが出来ます。
  3. コンフィギュレーション
  4. ビルド
  5. テスト
  6. インストール

実行方法編集

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" に型アノテーションを書くべきだと主張する人はまれなので、定数と変数の名前えらびは重要で、単に ab の様な「色のない」 名前は選ぶべきではありません。

暗黙の型変換は行われない編集

なお、いかなる数値型の変数についても暗黙の型変換( 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
なぜ?

基本データ型編集

数値編集

符号付き整数の型には、IntInt8Int16Int32Int64があります。Intは、32ビット環境ではInt32と同じサイズ、64ビット環境ではInt64と同じ。

符号無し整数の型には、UIntUInt8UInt16UInt32UInt64があります。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]

比較演算子編集

比較演算
文法 意味
< より小さい
<= 以下
> より大きい
>= 以上
文法 意味
== 等しい
!= 等しくない
=== 同じオブジェクトへの参照
!== 別のオブジェクトへの参照
文法 意味
~= パターンマッチ(左辺の範囲内に右辺が有ればtrue)
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結合演算子編集

nil結合演算子( Nil Coalescing Operator )
文法 意味
?? 左オペランドにはT?型、右オペランドにはT型の値をとり、
左オペランドに値が存在していればアンラップしてその値を返し、左オペランドがnilであれば右オペランドの値を返す
"x".toInt() ?? 0  // 0
"5".toInt() ?? 0  // 5

ビット演算子編集

ビット演算子
文法 意味
<< 左シフト
>> 右シフト(左オペランドが符号付き整数の場合は算術シフト、符号無し整数の場合は論理シフト)
& AND
| OR
^ XOR
~ NOT(ビット反転)

代入演算子編集

代入演算子
文法 意味
= 代入
+= 加算と代入
-= 減算と代入
*= 乗算と代入
%= 剰余演算と代入
/= 除算と代入
文法 意味
<<= 左ビットシフトと代入
>>= 右ビットシフトと代入
&= ビット演算ANDと代入
^= ビット演算XORと代入
|= ビット演算ORと代入
&&= 論理ANDと代入
||= 論理ORと代入

範囲演算子編集

範囲演算子( Range operators )
文法 意味
..< 半分開いた範囲(終端を含まない):半開区間
... 閉じた範囲(終端を含む):閉区間

キャスト演算子編集

キャスト演算子
文法 意味
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つ===は同じオブジェクトを参照しているかどうかを確認するための演算子を意味します。
  • whileiffor等の制御文が類似しています。
    • ただし、Swiftでは拡張機能を有します。例えば、whileif文はパターンマッチングや条件付きOptionalアンラップをサポートします。
  • 角括弧は、配列の宣言と配列の要素取得の両方で使用されます。

Objective-Cとの類似点編集

  • 基本的な数値型IntUIntFloatDouble等のサポート。
  • クラスメソッドは、インスタンスメソッドと同様に継承されます。クラスメソッド内のselfは、メソッドが呼び出されたクラスを意味します。
  • for...in列挙構文のサポート。

Objective-Cとの相違点編集

  • 文はセミコロン(;)で終わる必要はありません。しかし、1行に複数の文を記述する際に使用することができます。
  • ヘッダーファイルが存在しません。
  • /**/によるコメントはネストできます
  • 型推論のサポート。
  • ジェネリックプログラミングのサポート。
  • 関数は第一級オブジェクトです。
  • 演算子はクラスに対して再定義(演算子のオーバーロード)でき、新しい演算子を定義できます。
  • 文字列はUnicodeを完全にサポートします。ほとんどのUnicode文字は識別子や演算子でも使用できます。
  • 例外処理は存在しません。Swift 2では例外処理とは互換性のない別のエラー処理モデルが導入されています。
  • バグの原因となるC言語ファミリーの特徴がいくつか削除されています。
    • デフォルトでは、ポインタは公開されていません。プログラマが参照の管理をする必要はありません。
    • 変数割り当ては値を返しません。これにより、===の誤用を防ぐことができます。
    • switch文内でbreakを行う必要はありません。明示的にfallthroughを行わない限り次のcaseにフォールスルーすることはありません。
    • 変数と定数は常に初期化され、配列の境界は常にチェックされます。
    • 算術オーバーフローは実行時エラーとしてトラップされます。オーバーフローを許可する演算子は&+&-&*&/&%として定義されます。また、全ての整数型にはプロパティminmaxが定義されており、潜在的なオーバーフローのチェックに利用することができます。
    • ブロックを用いない1行のif文、while文はサポートされていません。
    • Off-by-oneエラーの原因となるC言語スタイルのfor (int i = 0; i < c; i++)文は、Swift 3で削除されました。
    • インクリメント演算子++、デクリメント演算子--は、Swift 3で削除されました。

脚註編集

  1. ^ 1.0 1.1 1.2 1.3 Accepted proposals for Swift 3.0

外部リンク編集