https://youtu.be/gLCs9ROS8Hc
今回も引き続き The Basics の 定数と変数
について眺めていきます。そんな中から、その定義方法みたいなところや、それぞれの特徴みたいなところを確認しながら、そこから窺い知れる Swift の特色みたいなところを見ていけたらいいなと思っています。どうぞよろしくお願いしますね。
——————————————————————— 熊谷さんのやさしい Swift 勉強会 #89
00:00 開始 01:12 定数や変数の名前付け 08:25 慣用的な変数名 10:21 変数を使いまわさない文化との相関性 16:42 変数名の命名規則 17:24 名前に値を関連づける 22:52 定数と変数の特徴 27:14 変数を使いまわさないことによる効能 30:58 状態の表現 33:43 状態を値に切り出す 36:10 質疑応答 36:20 k から始まる定数 40:32 ハンガリアン記法 43:11 次回の展望 ———————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #89
はい、じゃあ始めていきましょう。今日は定数と変数に関するスライドにいよいよ入っていく感じですね。前回はこのタイトルだけで1時間話せたということがすごいですね。それはそれで面白い話でしたので、興味があればアーカイブを見ていただけると嬉しいです。
今日はもう少し実践的なお話をします。スライドに沿って進めていきますので、初心に戻るような気持ちで進めていきましょう。初めてSwiftを学ぶ方や、あまり慣れていない方には良い再確認の機会となると思います。
前回少し触れましたが、名前と特性の値を関連付けるという話で終わったんでしたね。今日はもっと具体的に、どんな名前を付けるのかお話ししていきます。
例えば maximumNumberOfLoginAttempts
や welcomeMessage
といった変数名があります。これはなんとなく変数名が長いと感じる方もいるかもしれませんが、最近ではこれぐらい丁寧に書くほうが後々助けられることが多いです。なので、こういった長い名前を付けるのはおすすめです。
具体的には、変数として maximumNumberOfLoginAttempts
や welcomeMessage
といった名前を付けることがあります。特にメッセージ系の変数の名前を単に message
とするのではなく welcomeMessage
とすると、後々コードの中でどこを見ても扱っているメッセージが「ウェルカムメッセージ」であることがわかります。例えば、コード中の特定の行で message
が使われていると、どのメッセージを指しているのかその時点ではわかりません。しかし、welcomeMessage
であればそのメッセージが何を指しているのか一目瞭然です。
また、関数名でも同様に説明的な名前を付けることが重要です。例えば、makeWelcomeMessage
という関数で String
を返す場合、関数名からそのメッセージが「ウェルカムメッセージ」であることがわかります。これにより、コードの最後の方に return message
と書かれていても、この関数が「ウェルカムメッセージ」を作成していることが明確になります。最初から welcomeMessage
という名前を使うことで、コード全体が非常にわかりやすくなります。
確かに冗長に見えるかもしれませんが、理解しやすさのほうが優先されるべきです。スコープがもっと短い場合には、message
でも良いかもしれませんが、最近では長い名前でも自動補完機能を使えば簡単に入力できます。
さらに、同じような名前がたくさんあった場合でも、略称を使うこともありますが、Swiftでは厳密に保管してくれない場合もあるので注意が必要です。例えば、wm
や welcomeS
といった短縮形を試みても、うまく行かない場合があるため、なるべくフルネームを使う方が無難です。
これらを踏まえて、今日の勉強を進めていきましょう。 とりあえず使っていった方が可読性は向上するよという発想で、3行目も丁寧に書かれています。これも変数名を見ればよくわかるので、確かに悪くないでしょう。あとは、わかる範囲で省略していくこともできるかと思いますが、それも一つの方法です。
元のスライドに書かれていたものの方が、しっかりした感じがありますね。SwiftはAPIデザインガイドラインに従って、流暢な英語として読めるように名前をつけましょうというのがあります。そう考えると、3行目に書いてあるような形式になってくるのかなという感じがします。
一昔前のプログラマーは、msg
(メッセージの略)などの短い名前の方が馴染みやすいでしょう。また、さらに昔のプログラマーは変数名を1文字や2文字で書くことが一般的だったため、例えばi
などの高速化を目的とした省略記法が多かったようです。C言語では特にその傾向が強く、短く書くことが風潮としてありましたので、そういった書き方を好む人もいるでしょう。
昔の慣習で言えば、for
ループのカウンタをi
で表現するのが一般的でした。今でも1文字の変数が時折見かけられることがありますが、それは慣習的なものです。さすがに今ではほとんど使われませんが、メッセージを例えばm
と略すことはまだあるかもしれません。ただ、基本的には具体的な名前を付けることが推奨されています。名前を具体的にすることで、用途が限られるので使い回しがしづらくなりますが、逆に明確に分かりやすくなります。
現在では変数名を使い回さずに具体的な名前を付けるのが主流になってきたのは、変数のスコープが明確に分かれるからです。今、定数について説明していますが、let
を使っているためです。用途が明確であれば、限定した名前を付けるということです。
例えば、iOSでのUITextField
やラベルには具体的な名前を付けます。NSTextField
があるとき、ラベルのテキストとして適切な名前を付けます。MacOSではstringValue
になりますが、汎用的な名前は避けるべきです。
とにかく、こういった風に具体的な名前を付けて、そのプロパティも具体的な名前を付けていくことが大事です。 これはすごく汎用的な内容です。先ほどのウェルカムメッセージに関する部分とほとんど同等の表現力になっていますが、これはこれでラベルのテキストとして非常に良い表現になっています。型の場合、型名で説明がつけられるので特に難しいところはありません。汎用的すぎる場合でも問題ありません。
例えば、String
型の値であれば、「テキストフィールドのストリングバリュー」と言われれば表示するテキストに相当するということが理解できます。また、ある型がハッシュタグを表すものだとしましょう。その場合、「ハッシュタグのストリングバリュー」と言えばハッシュタグのテキストそのものだとわかります。また、UUID
のような型であれば、「ストリングバリュー」と言った場合、UUIDの文字列表現だろうと推測できます。このように、どこかしらで補完が効くような感じがします。
先ほどの「メッセージのスコープが狭ければ」という条件付きで話しましたが、「makeWelcomeMessage
」という関数名なら、その中で扱うメッセージはウェルカムメッセージだろうと推測できます。この程度の名前付けで十分な場合もあります。これは完全に私自身の感覚で話していますが、実際にはもっと良いアイディアがあるかもしれません。
あとは、使い回しするかしないかという観点についても考えます。例えば、テキストフィールドに関するものがあったときに、var textString
のような名前付けをすることが考えられます。しかし、これは必ずしもウェルカムメッセージが入るわけではないかもしれません。以前はメモリ空間が狭かったために変数名を広義にして使いまわしていた記憶がありますが、現在はその必要がなくなっています。
さて、スライドに戻りましょう。
Swiftのガイドラインにのっとった名前付けの一例が今表示されているスライドです。APIデザインガイドラインでは、変数名には型制約ではなく用途で名前を付けることが推奨されています。そのガイドラインに沿った名前の付け方がここで紹介されていますね。
変数や定数には特定の値を関連付けることができます。例えば、数字の10
や文字列のhello
などが例として挙げられますが、これらはリテラルです。リテラル以外にも、他の変数を関連付けることも可能です。
Swiftでの例を挙げると、まず1行目で定数a
に値10
を関連付けるとします。そして、定数b
に対しては定数a
を関連付けることもできます。このように、リテラルではない他の変数を関連付けることも可能です。
Swiftの大きな特徴として、構造体や列挙型があります。具体的な詳細を忘れてしまいましたが、他にも特徴的な点がありました。 とりあえず、値型と分類される型についてですが、代入時に原則として値がコピーされるという動きがあります。ここも変数の a
と関連付けるというところと絡む気がしますが、定数 b
はあくまでも a
の値と関連づいているのであって、定数 a
と関連づいているわけではないという点です。突き詰めていけば、最適化で同じものと見なされる可能性もゼロとは言えませんが、Swiftの場合、基本的には a
と b
はそれぞれ別の値に関連づいています。ここが別の値である可能性があるけれど、インスタンスとしては別という認識です。したがって、インスタンス a
に関連づけられているわけではないので、a
が何をされても b
には影響を及ぼしません。
例えば、これは変数だったとしても同じです。b
に a
を関連づけたからといって、b
には a
の値(つまり 10
)が関連づけられているのであって、a
自身が関連づけられているわけではありません。したがって、a
が書き換わったとしても b
はそのままです。この動きは、Swiftに慣れている人にはおなじみのもので、変数の関連付けという観点からも辻褄が合います。
クラスの参照型になると話が少し変わってきます。この場合、ポインターがあくまで関連づいているため、a
の内容を書き換えると b
の内容も書き換わるということが生じます。これは参照型の特徴であり、今回の話とは少し別な話になります。
何か話そうとしたことがあった気がしますが、とりあえず変数についてもう少し補足したいことがあった気がしますね。思い出したらお話ししますが、基本的なところを見てきているので、ここからいろいろと発見があると視野が広がって良いなと思います。何かあったらぜひコメントや声で教えてください。
ではスライドに戻ります。数字や文字、インスタンスの値なども関連づけることができますが、定数は値をセットしたら変更できないという特徴があります。変数は値をセットした後に異なる値をセットできるという特徴を示します。この使い分けが今どきの言語では当たり前ですが、当初のころはそこまで主流ではなかったように感じます。
以前の多くの言語では変数が存在していましたが、定数はあくまでオプションのようなもので、定数として属性をつけて使用する感じでした。例えば、マジックナンバーを避けるときに便利だったりします。画面に描画するときにラベルやビューを作る際、NSView
のフレームのオリジンの x
に 123
といった値を直接入れたりすると、後から見たときに「この 123
は何だろう」となってしまいます。
このように、Swiftでは定数と変数の使い分けがきちんとされています。次は具体的なコーディング例に移りたいと思います。 さて、まずは定数を使用する理由についてお話しします。例えば、これで何か数値 123
を入れていったときに、この 123
って何だろうと疑問に思うことがあるでしょう。また、片方を変更したときにもう片方も変更する必要があるので、そういう場面で定数を使うことが多いです。昔で言えば、C言語だと const int
のような感じですね。
例えば、次のように書きます。
let readingPoint = "x" // レスト何でもいいか?あらかじめ入れといて
このように定数として書いていくことで、マジックナンバーの代わりに名前を割り当てることができるのです。しかし、これは古典的な考え方です。
Swiftでは、定数が主力になり、変数が補助的な存在になっている印象があります。個人的には、定数が主役で、変数は補助的というほどではないかもしれないですが、重みとしてはそのような変化が見られます。
また、昔は変数が使い回しされることが多かったです。例えば、次のように変数を定義します。
var text = "a"
しかし、最近では変数の使い回しは少なくなっています。具体例として難しいですが、例えば次のように書きます。
let values = [1, 2, 3, 4]
let validValues = values.compactMap { $0 % 2 == 0 ? $0 : nil }
このようにして定数を使用すると、Swiftではこちらの方が自然に見えることが多いです。元の値を保持しつつ、有効な値だけを抽出し、名前を明確にすることで誤用を防ぐことができます。
例えば、sourceValues
とvalidValues
のように名前を使い分けることで、間違って変数名を混同することがなくなります。もしリターンをする場合でも、sourceValues
の方が明確で誤解が少ないでしょう。
局所スコープでデータを加工するときなどは定数を使い、プロパティのように状態が変化するものについては変数を使うと良いでしょう。具体例としては、次のようになります。
var textFieldValue: String = textField.value
このように、テキストフィールドの値は変更され得るものなので変数を使います。しかし、例えばラベルのテキストが初期化時から変わらない場合などは、定数として定義すると良いでしょう。
このような理由で、適切に定数と変数を使い分けることが大切です。 あんまり個人的には、型のフィールドを let
で定義するのに違和感を感じますね。なるべく var
にできないかなという発想が働くことがあります。ただ、今回はとりあえずこれでなんとかなりそうです。
こういった風に値が変化するもの、ある特定の時点で値が変わるものをプログラミングの言葉で「状態」と呼びます。その状態を表現する際に var
が適切で、場合によってはそれしか選択肢がないのかなと感じます。なので、僕は var
をよく使うようにしています。
今までの説明をまとめると、let
は定数を、つまり変わらない値を表現し、var
は状態を表現するものという感覚があります。このように捉えると、let
と var
をうまく使い分けられるのではないでしょうか。
例えば、let textFieldValue = textField.value
みたいなコードを書いているときに、テキストフィールドの値はその瞬間の状態を切り取ったもので、その後の値の変化とは関係ないですよね。時計を例に考えると、時刻は刻々と変わりますが、ある瞬間に見た時間は変わりません。その見た時間が let
のようなものです。一方、現在の時刻は var
です。こう考えると、let
は1次元(値)で、var
は2次元(値と時間)で表現されているように感じます。
以上が定数と変数の特徴の説明です。ここで、コメントを拾っていきますね。
フレームワークで k
から始まる定数があることについて話が出ていますが、そもそも k
の由来について知っている方いらっしゃいますか?言語によって使い方が異なるかもしれませんが、歴史的な背景がありそうですね。例えば、PascalやC言語などでも見かけた気がします。
コメントには g
とか、グローバル変数の接頭辞についてもいろいろありますね。g
が使われていたという話を聞いています。こういった接頭辞は、ネームスペースの衝突を避けるために使われていたのかもしれませんが、本当のところはどうなのか分かりません。 由来といえば、思い浮かぶのはC++です。メンバー変数にはm_
をつけるという特徴がありますね。C言語のクラスは「CValue」など頭に「C」が付き、プライベート変数の書き方が違います。C言語ではこう、C++はこうといった具合にです。例えば、インターフェースの命名規則では、関数名が「getValue」のように決まっています。C++ではm_
がプライベートで保護する内部属性だという規約があります。
他にも、Fortranではメンバー変数に特定の接頭辞をつける習慣があったりしました。コメントについてですが、C言語には方言が多く、標準的な命名規則やデザインガイドラインがあまり一般的ではありませんでした。当時は、アルゴリズムの実装に全力を注いでいた時代で、コードの命名規則に対する意識は低かったと思います。
現在では、アルゴリズムはパッケージとして提供されることが多くなり、コードの読みやすさが重要視されています。そのため、名前付けが重視されるようになったのだと思います。
他に、ハンガリアン記法というソースコードを書く際に特定の接頭辞を付ける方法があります。例えば、論理型変数には頭にb
をつけるなどです。メンバー変数にはm_
、グローバル変数にはg_
を付けるなどが慣用的な表現となっています。C++特有の言語仕様や機能、型名に依存する規約が多いです。
言語仕様としてコンパイラが弾くわけではないですが、慣用表現としてガイドラインに定められています。
ここに色々と例が書いてありますね。例えば、ロング型にはl_
を付けるなど、昔の流儀です。これらの考え方はSwiftではあまり使われなくなりました。Swiftではわかりやすい名前を情緒に重視して付けるのが主流です。
さて、時間になりましたので今日はここまでにしましょう。今日は名前の付け方と定数、変数の特徴について話しました。次回は構文的なところ、定義をどう書くかについて見ていこうと思います。
では、これで勉強会を終わりにします。お疲れ様でした。ありがとうございました。