目次
- 目次
- はじめに
- hello world
- コメント
- 定数
- 変数
- Swiftの基本的な型
- 演算
- if文
- switch文
- while文
- for文
- nilとオプショナル型
- Array(配列)
- tuple
- Set
- Dictionary
- function
- Class and method
- Computed Property
- Observer property
- Inheritance
- Static function and Static property
- cast
- Protocol
- extension
- struct
- 列挙型
- Generics
- Subscript
- guard
- Exception
- 参考資料
- MyEnigma Supporters
はじめに
最近、新しい言語の勉強として
Swiftを勉強しているのですが、
自分がC++とPythonユーザなので、
C++, Pythonユーザの観点から
Swiftの基本的な文法をまとめておきます。
hello world
Swiftでは標準出力に出力する関数は
pythonと同じprintなので、
下記でhello worldできます。
print("hello world")
文末のセミコロンは通常つけないようです。
(つけてもOK)
コメント
Swiftにおけるコメントは
C++と同じで、一行コメントはスラッシュ2個、
複数行コメントはスラッシュアスタリスクです。
//一行コメント /* 複数行 コメント */
ちなみににxcodeの場合、
cmd+/のショートカットでコメントアウトができます。
定数
定数は再代入不可能な変数です。
(C++のconst付き変数のようなもの)
Swiftで定数を設定する場合、
letという予約語を使って宣言します。
定数の宣言には2つ方法があり、
一つ目は定数宣言と同時に値を設定するものです。
let msg = "test" print(msg)
二つ目は定数の宣言と値の設定を分ける方法です。
この方法の場合、下記のサンプルのように、
定数宣言をする時に、型を指定する必要があります。
(一つ目の方法では、値から自動的に型が設定されていた)
let msg2: String msg2 = "test2" print(msg2)
変数
再代入可能な変数はvarという予約語で宣言します。
使い方はletの場合と同じです。
var msg = "test" print(msg) msg = "test3" print(msg) //再代入 var msg2: String msg2 = "test3" print(msg2)
Swiftの基本的な型
Swiftには下記のような型があります。
Int 整数値
Float, Double 小数値 (デフォルトはDouble)
String 文字列
Bool 真偽値
演算
基本的な演算方法は、他の言語とあまり変わりません。
// 数値演算 print(8 / 3) // 2 print(8.0 / 3) // 2.666.. print(8 % 3) // 2 余り var x = 10 x += 5 print(x) // 15 // 文字列演算 print("hello " + "world") print("x * 2 is \(x * 2)") //Stringへの埋め込み // 論理演算 print(true && false) // false print(true || false) // true print(!false) // true
一つ注意点はStringの中に変数の値を埋め込む場合は、
スラッシュの後に丸括弧で囲う必要があります。
if文
Swiftのif文はCの条件文の括弧の無い場合と同じような文法です。
let score = 50 let result: String if score > 80 { result = "great" } else if score > 60 { result = "good" } else { result = "bad" } print(result) // bad
switch文
Swiftのswitch文はC言語のものに似ていますがが、
条件の複数指定や、範囲指定、
または条件文に変数を取り込むことなどが可能です。
またC言語と違い、caseのそれぞれにbreakは不要です。
let num = 16 switch num { case 0: print("0") case 1, 2, 3: //複数指定 print("1/2/3") case 4...6: //範囲指定 print("4/5/6") case 7..<9: // 範囲指定(末尾を含まない) print("7/8") case 15: break //何もしない場合はbreak case let n where n > 20: //変数を受け取ることも可能 print("\(n) is huge!") default: print("default ") }
while文
while文もC言語と同じで、
条件文に括弧が無い形をしています。
var n = 0 while n < 3 { print(n) n += 1 }
またC言語のdo while文は少しSwiftでは異なり
repeat whileという予約語で実行されます。
n = 9 //実行されない while n < 3 { print(n) n += 1 } //一度実行される repeat { print(n) n += 1 } while n < 3
for文
for文はpythonの文法に似ていて、
in という予約語の後に、
範囲演算子(...)で数列を与えることで、
ループを回すことができます。
for i in 0...5 { print(i) }
また、Cやpythonにある、
breakやcontinueは同じようにそのまま使えます。
nilとオプショナル型
CでのNULL, pythonでのNoneのように、
空を意味するものでSwiftではnilという予約語を使います。
しかし、swiftの基本的な型では、
nilの代入を禁止しているため、
nilを使いたい変数はオプショナル型という型として
事前に初期化する必要があります。
下記のように、通常のStringにnilを代入しようとすると
エラーになりますが、
のこりの3つの方法でオプショナル型の変数として
初期化できるので、nilを代入できるようになります。
s2とs3は同じ意味です。
またオプショナル型として変数を初期化すると、
自動的に初期値はnilで初期化されます。
//let s1: String = nil //error let s2: Optional<String> = nil let s3: String? = nil let s4: String?
nilかどうがを判定して、
値を表示するには、
下記のようにします。
オプショナル型の値を取得する場合には
変数名の後に!が必要です。
// nil判定 if s2 != nil { print(s2!) // オプショナル型のデータを取り出す時は、!を付ける (unwrap) }
また下記のようにnilかどうかを判定する方法もあります。
s3がnil出ない場合のみ、valueに値がわたり、
その結果が表示されます。
// s3がnil出ない場合のみ、値を表示(Optional Binding) if let value = s3 { print(value) }
また、オプショナル型をprint文で表示させる場合は、
下記のような簡略型も使えます。
変数がnilの場合はthis is nilが表示され、
nilでない場合は、値が表示されます。
// s3がnilでなければ値を表示 print(s3 ?? "this is nil!")
Array(配列)
Swiftの配列(Array)は、Cに似ていて、
下記のように初期化できます。
// initialize var scores: [Int] = [50, 40] var scores2 = [50.0, 40.0] //型推論 var scores3: [String] //空Arrayで初期化 var scores4 = [String]() //上記と同じ
要素へのアクセスや代入も下記のようにできます。
要素数の計算や空集合判定が、
配列のメソッドで可能であることに注意しましょう。
print(scores[0]) // Arrayの要素を表示 scores[1] = 30 //Arrayの要素に代入 print(scores) //Array全体を表示 print(scores.count) // Arrayの要素数を計算 print(scores.isEmpty) // Arrayが空集合か判定
要素の追加に関しては、
pythonと同じく、appendでも可能ですし、
+= の演算子でも末尾に追加は可能です。
var names = [String]() names.append("Tom") names.append("Jon") names += ["Lisa"] for name in names { print(name) }
tuple
SwiftのタプルはPythonのtupleに近いですが、
若干文法が異なります。
まず、タプルの初期化はPythonと同じ丸括弧です。
異なる型のデータを入れることができます。
var items1 = ("cat", 5) //タプル作成
また、Pythonとは異なり、
タプルの要素にアクセスする場合は、
ドット(.)の後にインデックスを指定します。
printでタプルのすべての要素を表示することも可能です。
print(items1.0) //cat items1.1 = 8 print(items1)
また、それぞれの要素に名前をつけることもできます。
下記のコードの初めの例では、
タプルの返り値をそれぞれの名前の定数に割り当てています。
また二つ目の例のように、
使わない要素に関しては、アンダーバーで受け取ることにより、
データを使用しないことを意図できます。
最後の例は、tupleの初期化時に、
各要素に名前を付ける方法です。
この方法で初期化すると、
インデックスではなく、
要素の名前で要素にアクセスできます。
let (product, amount) = items1 print(product) print(amount) let (product, _) = items print(product) var items = (product: "milk", amount: 5) print(items.product)
Set
SwiftのSetはPythonのSetと目的は一緒で、
順序を持たない、重複を許さないデータを管理できます。
SwiftでSetを使う場合、
下記のように初期化します。
型推論も可能です。
var set: Set<Int> = [3, 5, 8, 8] //Setの初期化 var set2: Set = [3, 5, 8, 8] //型推論 print(set) var s = Set<Int>() //空のSetを作る
Setの中に値があるかのチェックや、
データの追加、削除、
そして要素数の取得は下記のメソッドできます。
print(set.contains(3))//3が入っているか? set.insert(10)//10を追加 set.remove(5)//5を削除 print(set.count)//要素の数を数える
PythonにおけるSetの集合演算も
下記のように実行できます。
let a: Set = [1, 3, 5, 8] let b: Set = [3, 5, 8, 9] print(a.union(b)) //和集合 print(a.intersection(b)) //積集合 print(a.subtracting(b)) //差集合
Dictionary
SwiftのDictionaryは、
PythonのDictionaryや
C++のmapと同様に、
KeyとValueから成るハッシュマップです。
SwiftのDictionaryは下記のように宣言します。
こちらも型推論が可能です。
var scored: Dictionary<String, Int> = ["tom": 200, "ken": 300] //Dictionary 初期化 var scored2 = ["tom": 200, "ken": 300] //型推論 let emptyd = [String: Int]() //空Dictionary
下記は、Dictionaryの使い方です。
一つ注意点は、DictionaryのKeyを指定した時には、
そのKeyが無い場合があるので、
オプショナル型で返り値が返ってくることです。
scored["tom"] = 500 //要素に代入 print(scored["lina"] ?? "n.a.") //ある要素の表示 scored["lina"] = 100 //新しい要素を追加 print(scored.count) //要素の表示 // Keyとvalueを表示 for (key, value) in scored { print("\(key): \(value)") }
function
関数を作る時は、下記のようにします。
関数の頭にfuncとつけて、
関数名, 返り値の型、引数の順番で書きます。
返り値が無い場合は、返り値の型は不要です。
func test1() { print("test1") } test1() func test2() -> String { return "test2" } print(test2())
引数に関しては、
書きのように引数名名: 型 = "デフォルト引数"
で指定できます。(デフォルト引数は省略可能です)
実際に使うときには、引数名を指定します。
(test4のように省略も可)
またその下の関数の例のように、
複数の引数名を指定することも可能です。
func test3(input: String = "aaa") {//default print("\(input)") } test3(input: "bbb") func test4(_ input: String) { print("\(input)") } test4("bbb") func test5(str input: String) { print("\(input)") } test5(str: "bbb")
ちなみにSwiftでは、上記の引数の指定方法では、
C++で言う所のconst引数扱いになり、
関数の中で書き換えることはできません。
C++における参照渡しにしたい場合は、
inoutという予約語を引数に設定し、
関数を呼ぶ時に、引数の前に&を付ける必要がります。
結果はC++の参照と同じです。
func add(x: inout Int) { x = x + 10 print(x) } var i = 10 add(x: &i) print(i)
Class and method
Swiftのクラスは下記のように作ります。
letでクラスのconstプロパティを、
varで通常のプロパティを設定できます。
C++でのコンストラクタは
initという関数(イニシャライザ)で表されます。
また、Pythonと同様、プロパティにはselfでアクセスします。
インスタンスの生成には、型推論を利用することも可能です。
class User { let name: String var age: Int init() { self.name = "Tom" self.age = 23 } } let user: User = User() let user2 = User() // 型推論 print(user.name) print(user.age) user.age = 26 print(user.age)
また下記のように、
イニシャライザをオーバライドしたり、
引数を与えたりすることができます。
クラスのメソッドは
クラスの中にfuncで指定すればOKです。
プロパティのselfは省略可能です。
class User { let name: String var age: Int init() { self.name = "Tom" self.age = 23 } init(name: String, age: Int) { self.name = name self.age = age } func sayHi(msg: String) { print("\(msg) \(name)") } } let user: User = User() let user2 = User() // 型推論 print(user.name) print(user.age) user.age = 26 print(user.age) let tom = User(name: "tom", age: 23) print(tom.name) print(tom.age) tom.sayHi("hi") let bob = User() print(bob.name) print(bob.age) bob.sayHi("hello")
一つswiftのクラスの注意点として、
クラスのオブジェクトを、
他のオブジェクトに=でコピーすると、
値ではなくポインタがコピーされる参照渡しになってしまいます。
値渡しのオブジェクトを作りたい場合は、
後述のstructを使う方法があります。
Computed Property
SwiftのComputed Propertyは、
C++にもPythonには無い文法だと思います。
これはいわゆるプロパティのゲッターとセッターを
簡単に記述する方法です。
下記のように、
それぞれのプロパティに対して、
そのプロパティにアクセスした時と、
そのプロパティに代入した時に呼ばれる処理を
記述することができます。
ちなみに、getterのみで良い場合は、
getやsetという予約語も不要な省略形を記述できます。
class User2 { let name: String var score: Int //computed property var level: Int { get { return Int(self.score / 10) } set { if newValue >= 0 { score = newValue * 10 } } } // getterのみの場合は省略形が使える var level2: Int { return Int(score / 20) } init(name: String, score: Int) { self.name = name self.score = score } } let tom2 = User2(name: "tom", score: 23) print(tom2.level) tom2.level = 5 print(tom2.score) tom2.level = -3 print(tom2.score) print(tom2.level2)
Observer property
Observe propertyもC++やPythonには無い
文法だと思います。
これはプロパティの監視をするための方法で、
あるプロパティが変更される時に、
変更される前と、変更された後に
自動実行される処理を簡単に記述できるようにしたものです。
Observer Propertyは各プロパティに
willSetとdidSetという予約語で指定され、
willSetはプロパティ変更の前、
didSetはプロパティ変更後に実行されます。
class User3 { let name: String var score: Int { willSet {// 変更前 print(Before change: "\(score) -> \(newValue)") } didSet {// 変更後 // after change print("After changed: \(score - oldValue)") } } init(_ name: String, _ score: Int) { self.name = name self.score = score } } let tom3 = User3("tom", 23) tom3.score = 33 tom3.score = 10
Inheritance
Swiftでの継承はclassの名前の後に、
コロンで親クラスを指定することで実現可能です。
親クラスのメソッドをオーバライドする時は、
funcの前にoverrideと書き、
逆にオーバライドを許可しない場合は、
親クラスのメソッドの前にfinalをつけます。
class User4 { let name: String var score: Int init(name: String, score: Int) { self.name = name self.score = score } func sayHi() { print("hi \(name)") } final func sayHiHi() {//オーバライド禁止する時はfinalを使う print("hiHi \(name)") } } // inheritance class AdminUser: User4 { func sayHello() { print("hello \(name)") } override func sayHi() { //親クラスのメソッドをオーバライド print("[admin] hi \(name)") } } let tom4 = User4(name:"tom", score: 23) let bob3 = AdminUser(name:"bob", score: 33) print(bob3.name) print(bob3.score) bob3.sayHi() bob3.sayHello()
Static function and Static property
インスタンスではなく、
クラスそのものに所属するメソッドやプロパティは、
C++と同様にstaticで設定することができます。
下記のように
staticやfuncやvarの前に置き、
static propertyにアクセスする場合は、
クラス名.static変数名とします。
class User5 { let name: String var score: Int static var count = 0 //static property init(_ name: String, _ score: Int) { self.name = name self.score = score User5.count += 1 } static func getInfo() { //static method print("number of instance: \(count) ") } } User5.getInfo() let tom5 = User5("tom", 23) User5.getInfo()
cast
クラスの型変換には、
swiftではasという予約語が使われます。
下記のように、継承された複数のクラスを
リストとしてまとめると、
swiftでは自動的に親クラスとしてまとめられます。
また、まとめられたリストの中で、
ある子クラスのものだけを取り出したい場合は、
下記のようにforループの中のif文の中で、
as?を使うと、AdminUser6のインスタンスのみを
抽出することができます。
class User6 { let name: String init(_ name: String) { self.name = name } } class AdminUser6: User6 {} let tom6 = User6("tom") let bob6 = AdminUser6("bob") let users = [tom6, bob6]//親クラスのUser6としてまとめられる。 for user in users { if let u = user as? AdminUser6 {//AdminUserのみ print(u.name) } }
Protocol
SwiftにおけるProtocolは、
C++で言う所の純粋仮想関数のようなもので、
継承する先のクラスに、
必ず実装する必要のあるメソッドやプロパティを
指定することができます。
下記のサンプルコードのように、protocolの後に、
プロトコルの名前を指定し、その後メソッドやプロパティを指定します。
プロパティに関しては、getとsetを指定することで、
読み書きの可能不可能を指定することが可能です。
protocol Printable { var type: String { get }//Readのみ可能なプロパティ var count: Int { get set }//ReadとWriteが可能なプロパティ func printout() } class User7: Printable { let type = "Laser" var count = 0 let name: String init(_ name: String) { self.name = name } func printout() { count += 1 print("\(type): \(count)") } } let tom7 = User7("tom") tom7.printout()
extension
extensionは、既存の型・クラスに
追加でメソッドなどを追加する方法です。
下記のように、String型に
lengthというメソッドを追加することができます。
extension String { var length: Int { return self.characters.count } } let msg0 = "hello" print(msg0.characters.count) print(msg0.length)
struct
クラスと似たデータ構造にstructがあります。
structはプロパティを持てたり、
メソッドを持ったり、ほぼクラスと同じ動きをしますが、
下記の2つが大きくことなります。
値型のデータで、=で値渡しが可能
メソッドの中でプロパティを変更するには、mutatingが必要
継承ができない。
あまりデータが頻繁に変わらないデータに使うようです。
struct User { var name: String init(_ name: String) { self.name = name } mutating func changeName() {//メソッドの中でプロパティを変更する self.name = name.uppercased() } } var original = User("tom") var copy = original // copy: originalの値 original.name = "bob" print(original.name) // bob print(copy.name) // tom
列挙型
C++で言う所のenumですが、
swiftのenumは,
それぞれの要素にcaseが必要です。
また、enumの要素に値をもたせることもできますが、
その値を利用するにはrawValueというプロパティに
アクセスする必要があります。
enum Direction { case right case left } var dir: Direction dir = Direction.right switch (dir) { case .right: print("right") case .left: print("left") } enum Direction2: Int { case right = 1 case left = -1 } print(Direction2.right.rawValue)
Generics
C++で言うところのテンプレートである、
Genericsは下記のように、
<>の中に汎用型名を指定して関数を作ればOKです。
様々な型に対応した関数を一つのコードで実現できます。
// Generics func getThree<T>(x: T) { print(x) print(x) } getThree(x: 5) getThree(x: "hello") getThree(x: 2.3)
Subscript
SubscriptはC++やPythonには無い機能だと思いますが、
自分で定義したクラスのインスタンスに対して、
ArrayやDictionaryのように、
インデックスやキーでアクセスできるようにするものです。
下記のコードのように、
自作のクラス内のインスタンスのプロパティに対して、
インデックスやキーでアクセスした時の
振る舞いを簡単に記述できます。
class Team { var members = ["ichiro", "matsui", "yuu"] subscript(index: Int) -> String { get { return members[index] } set { members.insert(newValue, at: index) } } } var team1 = Team() print(team1[1]) // matsui team1[3] = "tanaka" print(team1[3]) // tanaka
guard
guradはswirt特有のearly returnのための方法です。
下記のコードのように、
入力値がある条件を満たしているかを、
確認してから処理することは多いですが、
それをif文でやるとreturnを忘れたりするので、
明示的にguardという予約語を使うと、
コードの可読性が上がり、
また, return文を忘れるとエラーにしてくれます。
func say(_ msg: String?) { guard let s = msg else { print("value not set!") return } print(s) } say(nil) say("hello")
Exception
swiftにおける例外は、
機能としてはC++やPythonのものと
あまり変わりませんが若干文法が異なります。
まず下記のように、
例外の種類をenumで宣言して、
そこからエラーを投げる所で、
エラーをraiseします。
またエラーをraiseする関数には、
関数名の後にthrowsを入れます。
あとは、doとcatchで例外を補足できます。
enum LoginError: Error { case emptyName case shortName } class User0 { let name: String init(_ name: String) { self.name = name } func login() throws { guard name != "" else { throw LoginError.emptyName } guard name.characters.count > 5 else { throw LoginError.shortName } print("login success") } } let tom0 = User0("") do { try tom0.login() } catch LoginError.emptyName { print("please enter your name") } catch LoginError.shortName { print("too short") }
参考資料
MyEnigma Supporters
もしこの記事が参考になり、
ブログをサポートしたいと思われた方は、
こちらからよろしくお願いします。