前を向くために Part3

プログラミング、音楽、外交問題、その他思いついたことを何でも公開

人生、前向きに生きたいもの。でも、何かと後ろ向きになりがちな自分がいるのです。前向きに生きるには、まず前を向かなければなりませぬ。じゃあ前を向くためにはどうしたらいいの?と日々悩んどります。これはその記録の一部です。

Swift言語を超抄訳してみた

アップルが無償で公開している “Swift Programming Language” の中の “A Swift Tour” を超抄訳してみた。

定数、変数、オプショナル、タプル

定数は let を、変数は var を付ける。型は推測される。


let myConstant = 42
let myFloat = 42.0
var myVariable = 42

明示的に型を書く場合はコロン : の後に型名を書く。


let myDouble: Double = 42

オプショナル Optional は、特定のある値を持つか、または値を持たないという意味で nil を持つ。nil 値を取れる変数とも言える。宣言する場合には型名の後ろに ? を書く。


var optionalString: String? = "42"
optionalString = nil

タプル Tuple は複数の値の集まりである。中の要素の型が違ってもよい。要素を参照するには、名前か数字を使う。


let http404Error = ( 404, "Not Found" )
http404Error.0
http404Error.1

var httpError: ( code: Int, message: String)
httpError = http404Error
httpError.code
httpError.message

なお、値は自動的には型変換されないので、違う型に変換する必要がある場合は、明示的に型変換する。これは数値型同士でも必要。

let label = "幅は"
let width = 94
let widthLabel = label + String( width ) // ←型変換

ただし、文字列に何か値を埋め込む場合はバックスラッシュ+かっこ \() が使えるので便利。これを使えば明示的な型変換は不要。かっこの中では計算もできる。

let apples = 3
let oranges = 5
let appleSummary = "私は \( apples ) 個のリンゴを持っている。"
let fruitSummary = "私は \( apples + oranges ) 個の果物を持っている。"

配列とディクショナリ

配列やディクショナリを作るには大かっこ(ブラケット) [] を使う。ディクショナリとは、言ってみれば名前・値ペアのこと。その記法が配列と同じというだけの話。添字が文字列の配列とも言える。

var todaysShopping: [ String ]
var shoppingList = [ "魚", "水", "花", "インク" ]
shoppingList[ 1 ] = "水ボトル1本"
todaysShopping = shoppingList

var occupations = [
"まる子": "キャプテン",
"カイリ": "メカニック",
]
occupations[ "じゅん" ] = "広報"

空の配列やディクショナリを作るには、[][:] を使う。

shoppingList = []
occupations = [:]

フロー制御

条件分岐には ifswitch を、ループには for-inforwhiledo-while を使う。条件の部分にかっこを使うかどうかはどっちでもいい。ボディの部分に中かっこを付けるのは必須。

let individualScores = [ 75, 43, 103, 87, 12 ]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
teamScore

注)最後に teamScore とだけ書いてあるのは Xcode のプレイグラウンド内で変数の値を簡単に見るための方法である。

if

if 文において、条件は Boolean 式でなければならない。これはつまり if score {... はエラーということである。ゼロとの暗黙の比較は無い。

値が無いかもしれない場合には iflet を一緒に使うこともできる。こうした値はオプショナルが代表的である。

var optionalName: String? = "アップルのジョン"
var greeting = "こんにちは!"
if let name = optionalName {
greeting = "こんにちは, \( name )"
}

上記のコードで、もしオプショナルの値が nil の場合は、条件は false となり、ボディ内のコードはスキップされる。そうでなければ、オプショナルの値は let の後の定数に代入され、その値はボディブロックで使うことができる。

switch

スイッチ switch は、別に整数に限らず、またイコールかどうかにも限らず使える。default は必須。

let vegetable = "赤コショウ"
switch vegetable {
case "セロリ":
let vegetableComment = "レーズンを乗せるとおいしい。"
case "きゅうり", "クレソン":
let VegetableComment = "サンドウィッチに良い。"
case let x where x.hasSuffix( "コショウ" ):
let vegetableComment = "これ辛い \(x) かな?"
default:
let vegetableComment = "みんなスープには良い。"
}

let でパターンの比較部分に合致する定数へ代入するときに使えることとその使い方に注目。

合致する switch case の中のコードを実行した場合、プログラムはスイッチ文から抜け、次のケースを実行することはない。なので break を明示的に case の最後につける必要はない。

for

for-in においてディクショナリーを使う場合、ディクショナリーは順序のないコレクションなので、ループを実行する順序は不定である。

let interestingNumbers = [
"素数": [ 2, 3, 5, 7, 11, 13 ],
"フィボナッチ": [ 1, 1, 2, 3, 5, 8 ],
"2乗": [ 1, 4, 9, 16, 25 ],
]
var largest = 0
for ( kind, numbers ) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
largest

while, do-while

while (と do-while)は条件が変わるまでコードブロックを繰り返すのに使える。ループの条件は最後でもよく、この場合、ループは最低1回は実行される。

var n = 2
while n < 100 {
n = n * 2
}
n

var m = 2
do {
m = m * 2
} while m < 100
m

..< と ...

ループのインデックスのレンジを指定したり、明示的に初期化したり条件を付けたり増分を指定するのに、..<... という範囲(レンジ)演算子が使える。以下の3つのループは同じことをしている。

var firstForLoop = 0
for i in 1..<4 {
firstForLoop += i
}
firstForLoop

var secondForLoop = 0
for var i = 1; i < 4; ++i { // この場合は ++i でも i++ でも同じで、値は 1, 2, 3 を取る。
secondForLoop += i
}
secondForLoop

var thirdForLoop = 0
for i in 1...3 {
thirdForLoop += i
}
thirdForLoop

関数とクロージャ

関数を宣言するには func を使う。呼び出すには関数名に続けてかっこ内に引数のリストを入れる。関数の戻り値の型と引数の名前や型を分離するには -> を使う。

func greet( name: String, day: String ) -> String {
return "Hello \( name ), today is \( day )."
}
greet( "Bob", "Tuesday" )

関数から複数の値を返す場合などにはタプルを使う。

func calculateStatistics(scores: [Int] ) -> ( min: Int, max: Int, sum: Int ) {
var min = scores[ 0 ]
var max = scores[ 0 ]
var sum = 0

for score in scores {
if score > max {
max = score
else if score < min {
min = score
}
sum += score
}

return ( min, max, sum )
}
let statistics = calculateStatistics( [ 5, 3, 100, 3, 9 ])
statistics.sum
statistics.2

関数は、可変の数の引数を取ることもでき、それらは配列としてまとめられる。

func sumOf( numbers: Int... ) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}

sumOf()
sumOf( 42, 597, 12 )

関数はネスト可能。ネストされた内側の関数は外側の関数の変数等にアクセスすることができる。長かったり複雑だったりする関数を分割してわかりやすくすることにも使える。

func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()

関数はファーストクラスな型である。つまり、関数は、別の関数を戻り値として返すことができるということである。

func makeIncrementer() -> ( Int -> Int ) {
func addOne( number: Int) -> Int {
return 1 + number
}
return addone
}
var increment = makeIncrementer()
increment( 7 )

関数は別の関数を引数のひとつとして取ることができる。

func hasAnyMatches( list: [ Int ], condition: Int -> Bool ) -> Bool {
for item in list {
if condition( item ) {
return true
}
}
return false
}
func lessThanTen( number: Int ) -> Bool {
return number < 10
}
var numbers = [ 20, 19, 7, 12 ]
hasAnyMatches( numbers, lessThanTen )

関数は実はクロージャ、つまり後で呼び出すことができるコードブロックの特別なケースである。クロージャのコードは、クロージャが作られた時のスコープで利用可能な変数や関数などに、たとえそのクロージャの実行時に違うスコープであっても、アクセスすることができる。例としてあげられるのはネストされた関数である。クロージャは、中かっこで囲むことで、名前無しで書くことができる。引数と戻り値の型をボディから分離するには in を使う。

numbers.map({
( number: Int ) -> Int in
let result = 3 * number
return result
})

クロージャはもっと簡潔に書く方法がいくつかある。クロージャの型が、デリゲートのコールバックのようにすでにわかっている場合は、引数の型、戻り値の型、あるいはその両方を省略することができる。文が1つのクロージャは暗黙としてその文の値を返す。

let mappedNumbers = numbers.map({ number in 3 * number })
mappedNumbers

引数には、名前ではなく番号で参照することもでき、これは特に非常に短いクロージャで便利である。ある関数への最後の引数として渡されたクロージャはかっこのすぐ後に現れても良い。

let sortedNumbers = sorted( numbers ) { $0 > $1 }
sortedNumbers

オブジェクトとクラス

クラスを作るには、class の後にクラス名を続ける。クラス内のプロパティの宣言は、それがクラスのコンテキストの中であるという点を除けば、定数や変数と同じ方法で書ける。同様に、メソッドと関数も、同じ方法で書ける。

class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \( numberOfSides ) sides."
}
}

クラスのインスタンスを作るには、クラス名の後ろにかっこを書く。インスタンスのプロパティやメソッドにアクセスするにはドット記法を用いる。

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

上のバージョンの Shape は重要なもの、つまりインスタンスが作られた時にクラスをセットアップするイニシャライザが欠けている。それを作る場合は init を使う。

class NamedShape {
var numberOfSides: Int = 0
var name: String

init( name: String) {
self.name = name
}

func simpleDescription() -> String {
return "A shape with \( numberOfSides) sides."
}
}

self はこういう時にこう使うという例である。プロパティはどれも値を持つ必要があるが、それは numberOfSides のように宣言時に初期化するか、またはイニシャライザの中で行う。

オブジェクトが解放される前に何かクリーンアップが必要な場合は、deinit を使ってデイニシャライザを作る。

サブクラスは、サブクラス名の後にコロンを続けてスーパークラス名を含める。クラスを作るのにスーパークラスはあってもなくても良い。

スーパークラスの実装をオーバーライドするサブクラスのメソッドは、override とマークを付ける。これがないとコンパイルエラーになる。また、実際にはオーバーライドしていないメソッドoverride を付けてもコンパイルエラーになる。

class Square: NamedShape {
var sideLength: Double

init( sideLength: Double, name: String ) {
self.sideLength = sideLength
super.init( name: name )
numberOfSides = 4
}

func area() -> Double {
return sideLength * sideLength
}

override func simpleDescription() -> String {
return "A square with sides of length \( sideLength )."
}
}
let test = Square( sideLength: 5.2, name: "my test square" )
test.area()
test.simpleDescription()

単純なプロパティに加えて、プロパティはゲッターとセッターを持てる。

class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0

init( sideLength: Double, name: String ) {
self.sideLength = sideLength
super.init( name: name )
numberOfSides = 3
}

var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newNalue / 3.0
}
}

override func simpleDescription() -> String {
return "An equilataral triangle with sides of length \( sideLength )."
}
}
var triangle = EqualateralTriangle( sideLength: 3.1, name: "a triangle" )
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength

perimeter のセッターの中に、新しい値が暗黙の名前 newValue を持っているが、これは明示的に set の後にかっこでくくって名前を付けることもできる。

イニシャライザが3つの異なるステップを持っていることに注目。

  1. サブクラスで宣言されているプロパティの値をセットする。
  2. スーパークラスのイニシャライザを呼び出す。
  3. スーパークラスで定義されているプロパティの値を変更する。メソッドやゲッターやセッターを使うその他の追加セットアップはこの時点で行うことができる。


もし、プロパティを計算する必要はないけれども、値をセットする前や後にコードを走らせる必要がある場合は、willSetdidSet を使う。例えば、下の例では、正三角形の1辺の長さが常に正方形の1辺の長さと同じであることを確実にする。

class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init( size: Double, name: String ) {
square = Square( sideLength: size, name: name )
triangle = EquilateralTriangle( sideLength: size, name: name )
}
}
var triangleAndSquare = TriangleAndSquare( size: 10, name: "another test shape" )
triangleAndSquare.square.sideLength
triangleAndSquare.triangle.sideLength
triangleAndSquare.square = Square( sideLength: 50, name: "larger square" )
triangleAndSquare.triangle.sideLength

クラスにおけるメソッドは、関数との重要な違いが一つある。引数の名前は、関数においては関数の中でのみ使用されるが、メソッドにおいてはメソッドを呼び出す際にも使われるというということだ(1番目の引数を除く)。デフォルトでは、メソッドは引数名を呼び出し時と内部とで同じ名前で持つが、内部だけで使う2番目の名前を指定することもできる。

class Counter {
var count: Int = 0
func incrementBy( amount: Int, numberOfTimes times: Int ) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy( 2, numberOfTimes: 7 )

オプショナル値の場合は、メソッド、プロパティ、添字などのような演算の前に ? を書くことができる。もし ? の前の値が nil ならば、? の後ろすべてが無視され、式全体の値が nil になる。そうでなければ、オプショナル値が解かれ、? の後ろのすべてにおいて解かれた値が用いられる。どちらの場合も、式全体の値がオプショナル値である。


let optionalSquare: Square? = Square( sideLength: 2.5, name: "optional square" )
let sideLength = optionalSquare?.sideLength

列挙型と構造体

列挙型を作るには enum を使う。クラスや他のすべての名前付き型と同様に、列挙型もそれに関連したメソッドを持てる。


enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String( self.rawValue )
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue

この例では、列挙型の生の値の型は Int であるから、最初の生の値をを指定さえすればよい。残りの生の値は順番に割り当てられる。生の値の型は文字列型も浮動小数点型も使える。列挙型のメンバーの生の値にアクセスする場合は rawValue プロパティを使う。生の値から列挙型のインスタンスを作る場合は init?(rawValue:) イニシャライザを使う。


if let convertedRank = Rank( rawValue: 3) {
lewt threeDescription - convertedRank.simpleDescription()
}

列挙型のメンバーの値は実際にその値であり、単に生の値の別の書き方というわけではない。実際、もし意味のある生の値が無い場合は、付ける必要も無い。


enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()

構造体を作るには struct を使う。構造体は、メソッドやイニシャライザも含めて、クラスと多くの同じ動作をサポートする。最も重要な違いの一つは、コード内で構造体が渡される時には常にコピーされるのに対し、クラスは参照が渡されるということである。


struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \( rank.simpleDescription() ) of \( suit.simpleDescription() )"
}
}
let threeOfSpades = Card( rank: .Three, suit: .Spades )
let threeOfSpadesDescription = threeOfSpaces.simpleDescription()

列挙型のメンバーのインスタンスは、そのインスタンスに関連付けられた値を持つことができる。同じ列挙型の複数インスタンスがそれぞれのインスタンスに関連付けられたことなる値を持つこともできる。値は、インスタンスを作るときに設定する。関連付けられた値と生の値は違うものである。列挙型のメンバーの生の値はすべてのインスタンスを通して同じであり、列挙型を定義するときに決められる。

以下の例参照。


enum ServerResponse {
case Result( String, String )
case Error( String )
}

let success = ServerResponse.Result( "午前6時", "午後8時9分" )
let failure = ServerResponse.Error( "チーズを切らした" )

switch success {
case let .Result( sunrise, sunset ):
let serverResponse = "日の出は \( sunrise ) で日の入りは \( sunset )。"
case let .Error( error ):
let serverResponse = "失敗...( error )"
}

スイッチケースに対する値マッチングの一部として ServerResponse の値が日の出と日の入りの時刻にどのように展開されるかに注目。

プロトコルとエクステンション

プロトコルを宣言するには protocol を用いる。


protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}

クラス、列挙型、構造体はすべてプロトコルに適合する。


class SimpleClass: ExampleProtocol {
var simpleDescription: String = "とても短いクラス。"
func adjust() {
simpleDescription = "100% アジャストした。"
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "シンプルな構造体"
mutating func adjust() {
simpleDescription += " (アジャスト済み)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription

クラスの場合は mutating が不要だが構造体の場合は必要なことに注目。クラスではメソッドは常にクラスを変更可能だけれども構造体はそうではないからというのがその理由。

新しいメソッドや計算したプロパティのような機能追加をすでに存在する型に行う場合は、extension を用いる。プロトコル準拠を型に追加するにもエクステンションを使う。ライブラリやフレームワークからインポートした型にもエクステンションは使える。


extension Int: ExampleProtocol {
var simpleDescription: String {
return "数字 \( self )"
}
mutating func adjust() {
self += 42
}
}
7.simpleDescription

プロトコル名は、他のどんな名前付き型と同じように使える。例えば、型はみんな異なるけれども、みんな同じ単一のプロトコルに準拠する、というような場合に使える。プロトコル型の値を扱う場合、プロトコル定義以外のメソッドは利用できない。


let protocolValue: ExampleProtocol = a
protocolValue.simpleDescription
// protocolValue.anotherProperty ←コメントを外すとエラー。

protocolValueSimpleClass のランタイム型だとしても、コンパイラはこれを ExampleProtocol の与えられた型として扱う。つまり間違えてこのプロトコル準拠に加えてクラスが実装するメソッドやプロパティにアクセスすることはできない。

ジェネリック

ジェネリックな関数や型を作るには名前を <>かっこで囲んで書く。


func repeat< Item > ( item: Item, times: Int ) -> [ Item ] {
var result = [ Item ] ()
for i in 0..<times {
result.append( item )
}
return result
}
repeat( "knock", 4 )

ジェネリックな形の関数やメソッドも、クラス、列挙型、構造体と同様に作ることができる。


// Swift 標準ライブラリのオプショナル型の再実装

enum OptionalValue<T> {
case None
case Some( T )
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some( 100 )

要求仕様のリストを指定するには、where を型名の後に書く。要求仕様とは、例えばプロトコルに準拠したり、2つの型を同じであるように要求したり、クラスが特定のスーパークラスを持つように要求するとか、そういうことである。


func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> ( lhs: T, rhs: U ) -> Bool {
for lhtItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements( [ 1, 2, 3 ], [ 3 ] )

単純な場合は、where を省略し、単にコロンに続けてプロトコルやクラス名を書く。<T: Equatable><T whereT: Equatable> と同じである。

(終わり)