SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

アップルの新プログラミング言語「Swift」を探検しよう

Swiftの「クラス」と「ストラクチャ」 その① ~ プロパティ、メソッド、継承、ライフサイクル

アップルの新プログラミング言語「Swift」を探検しよう 第4回


メソッド

 Objective-Cのクラスと同様に、Swiftのクラスとストラクチャにはメソッドを定義できます(もちろん前回述べたとおり、列挙型に対しても定義可能です)。

外部引数名に対する挙動

 本連載第2回で述べたように、Objective-Cでは、以下のような2つ目の引数以降にラベルを付けたメソッドが多く見られます。

NSObject *obj = [NSObject new];
[obj performSelector: @selector(description)
          withObject: nil
          afterDeley: 1.0f]; //各引数をラベルで説明する

 Swiftのメソッド宣言でもこの記法を踏襲しています。そのため、関数の引数とは宣言方法と動作が少し異なります。

  • 第1引数 …… 内部引数のみを示す(関数と同じ)
  • 第2引数以降 …… 内部引数が外部引数名も示す(関数の「#」による外部引数名の略記法と同じ)

 次の例では、printString()メソッドを呼び出す際、第2引数に外部引数名withTimesも書いています。printString()メソッドでは引数を(string: String, withTimes: Int)と宣言していますから、関数であれば外部引数名は使用できません(内部引数に「#」を付ける必要がある)。

class CustomPrinter {
    func printString(string: String, withTimes: Int) {
        for _ in 1...withTimes {
            print(string)
        }
    }
}
let printer = CustomPrinter()
printer.printString("Wow!!", withTimes: 3) // Wow!!Wow!!Wow!!

 第2引数以降で外部引数名を使いたくない場合には、内部引数の前に「_」(アンダースコア)を付けます。また、第1引数に外部引数名を持たせたい場合には、関数と同じように明示的に外部引数名を宣言します。

class CustomPrinter {
    // 第1引数に外部引数名を持たせ、第2引数を_で省略
    func mprint(string str: String, _ withTimes: Int) {
        for _ in 1...withTimes {
            print(str)
        }
    }
}
let printer = CustomPrinter()
printer.mprint(string: "Yea!!", 4) // Yea!!Yea!!Yea!!Yea!!

 

mutatingキーワード(副作用の明示)

 まず、次の例を見てください。CustomRangeストラクチャの宣言後、そのインスタンスからincrementStart()メソッドを2回呼び出していますが、incrementStart()メソッドによりstartプロパティの値が更新されるため、両者で実行結果が異なっています。

struct CustomRange {
    var start: Int = 0
    var length: UInt = 0
    mutating func incrementStart() {
        start++
    }
}
var range = CustomRange()
range.start = 2
var beforeincrement = range.start // 2
range.incrementStart()
var afterincrement = range.start // 3

 ストラクチャでは、呼び出したときにこのような副作用(値や状態などの更新)を伴うメソッドにはmutatingキーワードを付ける必要があります。この例では、incrementStart()メソッドにmutatingキーワードが付けられています。クラスに対しては同様の操作にmutatingキーワードは必要ありません。

 メソッド呼び出しの前後で内部状態が変わるかもしれないことを他のプログラマが知るには、ストラクチャ(あるいは列挙型)内部の実装を見るか、実際に動作させるか、メソッド名から想像するくらいしか方法がありません。本連載第1回でも少し触れましたが、副作用を伴うメソッドは、意図しない結果を生む可能性を高くします。使用対象は値型に限られていますが、このように副作用があることを明示すれば、プログラマがバグを埋め込みにくくなります。

 なお、mutating付きメソッドを利用する予定のあるインスタンスは常に変数に代入します。値型の定数についた値型プロパティは変更できず、mutating付きメソッドを呼び出すと値型プロパティに対して変更が加わる可能性があるためです。

let range = CustomRange()
range.incrementStart() // エラー

 なお、ストラクチャと同じ値型である列挙型でも、計算プロパティで内部状態を変更するメソッドにmutatingキーワードを付ける必要があります。

 また、値型のmutatingキーワードを付けたメソッドでは、次のようにして、呼び出しインスタンスそのものを入れ替えることが可能です。

struct CustomRange {
    let start: Int = 0
    var length: UInt = 0
    mutating func moveStart(start: Int) {
        self = CustomRange(start:start, length:self.length)
    }
}
var range = CustomRange // start: 0, length: 0
range.moveStart(2)
range // start: 2, length: 0

 Objective-Cでは、自分のインスタンスを参照するためにクラス内からselfを用いてプロパティやメソッドにアクセスしていましたが、mutatingキーワードを付けたメソッド内であれば、このselfをごっそり入れ替えれることが分かります。

 上記の例では、startのプロパティは後から変更できないためにmutatingメソッド内でインスタンスそのものを入れ替えています。

次のページ
継承

この記事は参考になりましたか?

アップルの新プログラミング言語「Swift」を探検しよう連載記事一覧

もっと読む

この記事の著者

yad(ヤド)

クラスメソッド株式会社のアプリケーションエンジニア。iPhoneアプリケーションの開発に2年以上従事している。開発に使用するObjective-Cのみならず、関数型言語Haskellや機械学習などにも関心がある。「Developers.IO」に寄稿した記事の一覧

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/7898 2014/08/09 21:40

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー