書いて覚えるSwift入門

第34回 The value of the property

この記事を読むのに必要な時間:およそ 3.5 分

プロパティの(価)

前回予告したとおり,今回はカジュアルな話題です。題して⁠The value of the property”。⁠プロパティの値」とも「プロパティの価値」とも邦訳できますが,その双方の意味を込めています。

しかしそもそも「プロパティ」って何でしょう?

iOSの辞書によると図1)⁠⁠財産」⁠不動産」⁠属性」⁠所有権」そして一周回って「プロパティ」と出てきますが,いずれも共通しているのは「固有の何か」⁠たとえばファイル。ファイルの内容が「値」なら,ファイル名や更新日時などのメタデータは「プロパティ」⁠⁠固有値」という訳がよさそうなのですが,この言葉は数学における⁠eigenvalue⁠という言葉に「取られて」しまったおかげか,ITの世界では「プロパティ」というカタカナで落ち着いたようです。

図1 iOSの辞書でプロパティを検索

図1 iOSの辞書でプロパティを検索

値の中の値

それではSwiftにおけるプロパティとはいったいなんでしょうか? 断言する前に実例を見てみましょう。Playgroundで次を入力してみてください。

"swift".description          // "swift"
(42).description              // "42"
(42.195).description      // "42.195"
[42].description              // "[42]"
["swift":4.1].description
           // "["swift": 4.0999999999999996]"

それぞれの値を文字列にしたものが""に囲まれて表示されているはずです。これがそれぞれの値(value)に対する.descriptionという名のプロパティ(property)で,英語のdescription=説明という名のとおり,それぞれの値の説明になっています。

今度は.description.hashValueにしてみましょう。StringIntDoubleではこのようにIntの値が出てきますが……,

"swift".hashValue   // 4799434080856491603
(42).hashValue       // 42
(42.195).hashValue  // 4631135235630652457

ArrayDictionaryだとエラーになります図2)⁠

図2 ArrayやDictionaryではエラー発生

[42].hashValue                 // error: value of type '[Int]' has no member 'hashValue'
["swift":4.1].hashValue   // error: value of type '[String : Double]' has no member 'hashValue'

どんな値がどんなプロパティを持つかは,(type)によって決まります。

今そこにあるプロパティ・その場で作られるプロパティ

プロパティは型によって決まる。具体的にその様子を見てみましょう。

struct Point<T:FloatingPoint> {
    var x:T
    var y:T
}

PointというStructを作ったうえで使ってみます。

var dp = Point(x:3,y:4)
dp.x // 3
dp.y // 4

.x.yというプロパティが存在し,初期化したとおりの値となっています。これをストアド・プロパティ(stored property)と言います。Cの構造体(struct)のメンバに相当します。

このPointに原点(0,0)から距離を返す.distanceというプロパティを付け加えてみましょう。

import Darwin // for sqrt()

extension Point {
    var distance:T {
        return sqrt(x*x + y*y)
    }
}

実行結果は次のとおり。

dp.distance // 5

メモリにそのまま保持されているストアド・プロパティに対し,演算された結果はコンピューテッド・プロパティ(computed property)と言います。

「あれ? これってメソッド(method)じゃね?」と思った読者のあなたは鋭い。実は本質的に同じことなのです。

extension Point {
    func getDistance() -> T {
        return sqrt(x*x + y*y)
    }
}

dp.getDistance() // 5

ここで.getDistance()()を取ってみましょう。エラーにはならず,() -> Doubleと出てくるはずです。

そうなのです。Swiftではメソッドもまた単なる関数型のストアド・プロパティに過ぎず,コンピューテッド・プロパティは()を付けずに実行されるメソッドにすぎないのです。

しかし,Swiftのコンピューテッド・プロパティにはそれ以上のことができます。ストアド・プロパティを上書きすることもできるのです。

.distanceの定義を次のように変えてみます。

extension Point {
    var distance:T {
        get {
            return sqrt(x*x + y*y)
        }
        set {
            let d = distance
            x *= newValue / d
            y *= newValue / d
        }
    }
}

すると……,

dp.distance = 10
dp.x // 6
dp.y // 8

これは,次と等価と言えるでしょう。

extension Point {
    func getDistance() -> T {
        return sqrt(x*x + y*y)
    }
    mutating func setDistance(_ newValue:T) {
        let d = self.getDistance()
        x *= newValue / d
        y *= newValue / d
    }
}

ほかの言語でも,値を取得するプロパティ(や言語によっては属性[attribute]⁠をgetter,値を変更するプロパティをsetterと言いますが,Swiftのプロパティはその双方に対応しています。どんな場合にどちらを用いるべきかというのはスタイルの問題になりますが,Swiftはプロパティとメソッドの違いは()の有無に過ぎず,どちらもプロパティという立場をとっています。

著者プロフィール

小飼弾(こがいだん)

1969年生まれ,東京都出身。元ライブドア取締役の肩書きよりも,最近はPokemon GOのガチトレーナーのほうが有名になりつつある……かもしれない永遠のエンジニアオヤジ。

活躍の場はIT業界だけでなく,サブカルからアカデミックまで多方面にわたり,ネットからの情報発信は気の向くまま毎日毎秒! https://twitter.com/dankogai,ニコニコチャンネルは,http://ch.nicovideo.jp/dankogai,blogはhttp://blog.livedoor.jp/dankogai/

当社刊行書籍は『小飼弾のアルファギークに逢ってきた』『小飼弾のコードなエッセイ』など。他にも著書多数。

コメント

コメントの記入