【Ruby学習記録】変数とその利用方法
お題1:氏名を文字列で、年齢を整数で、それぞれ変数に代入せよ
# お題1
name = "Masahiko Iwakiri"
birthday = Time.local("1977-05-07")
age = ((Time.now.localtime - birthday) / 60 / 60 / 24 / 365).floor
# お題的には下記でOK
age = 45
これは、Rubyでの変数の宣言の仕方、代入の仕方を確認するお題。
Rubyの場合は、あらかじめの変数宣言は特に必要なく、いきなり初出の変数に代入してしまってOK。
Rubyはオブジェクト指向で、すべての変数は何らかのクラスのインスタンスになるのだが、いきなり代入した場合は、その代入値によって自動的に型が決まる仕様になっている。
なので、上記の例だとそれぞれ下記のようになる。
- name : 文字リテラルを代入してるので String
- birthday : Time.local メソッドの戻り値を代入してるので Time
- age : 整数値を代入しているので Integer
このお題の趣旨としては、birthday は必要ないのだが、「年齢」ということなんでちゃんと計算して出してみよう、という次第。
お題2:変数展開を使って、氏名と年齢を以下のように表示せよ
"私の名前は<あなたの名前>です。年齢は<あなたの年齢>才です。"
# お題1
name = "Masahiko Iwakiri"
birthday = Time.local("1977-05-07")
age = ((Time.now.localtime - birthday) / 60 / 60 / 24 / 365).floor
# お題2
puts "私の名前は#{name}です。年齢は#{age}才です。"
これは、以前のお題で既に使ったテクニックで、『変数展開・式展開』というテクニック。
文字リテラルを""で表した場合は、#{変数名・式} という記述で、リテラル内に変数や式の結果を埋め込める、というもの。
Rubyの文字リテラルは''でも表現できるが、その場合は「変数展開・式展開」は使えない。
*エラーになるわけではなく、#{変数名・式} がそのまま文字列として出てくる。
お題3:変数を使って、「年齢-5」になるような再代入の処理を記述せよ
変数はプログラム内で任意に値が変更できる、ってことでそれをやってみましょう、というお題。
# お題1
name = "Masahiko Iwakiri"
birthday = Time.local("1977-05-07")
age = ((Time.now.localtime - birthday) / 60 / 60 / 24 / 365).floor
# お題2
puts "私の名前は#{name}です。年齢は#{age}才です。"
# お題3
age -= 5
puts "私の名前は#{name}です。年齢は#{age}才です。"
===
$ ruby q.rb
私の名前はMasahiko Iwakiriです。年齢は45才です。
私の名前はMasahiko Iwakiriです。年齢は40才です。
なお、プログラムの世界では、変数と似たような使い方をするものに「定数」というものがある。
これは、変数とは違い、最初に設定した値をプログラム内でずっと使い続けたい場合に用いるもの。
他のプログラム言語では、変数と定数で宣言の仕方が違うケースもあるのだが、Rubyの場合は「名前の先頭を英大文字」にするだけで「定数」という扱いになる。(慣例としては、変数はすべて小文字、定数はすべて大文字という使い分けが多い)
# 変数
name = "Masahiko Iwakiri"
name = "hoge"
# 定数
AGE = 45
AGE = 40
puts "私の名前は#{name}です。年齢は#{AGE}才です。"
===
$ ruby q.rb
q.rb:6: warning: already initialized constant AGE
q.rb:5: warning: previous definition of AGE was here
私の名前はhogeです。年齢は40才です。
ただ、Rubyの場合、定数の扱いはそこまで厳密ではないようで、上記のように記述した場合、警告メッセージは出るものの、定数であるはずの値を変更は出来てしまう。
それを防ぐための freeze というメソッドがあるようだが、どうもそれでも上記のような再代入による値の変更は防げないようだ。
freeze は「破壊的メソッド」と言われるようなメソッドでの操作を防ぐためのものらしい。
このfreezeメソッドも結構癖があるみたいで、
NAME = "Masahiko Iwakiri"
NAME.freeze
NAME.upcase!
puts NAME
===
$ ruby q.rb
MASAHIKO IWAKIRI
このように、定数に値を代入してからその変数にfreezeメソッドを使っても値の書き換えは防げない。
NAME = "hogehoge" .freeze
NAME.upcase!
puts NAME
===
$ ruby q.rb
q.rb:2:in `upcase!': can't modify frozen String: "hogehoge" (FrozenError)
こういうふうに、代入と同時にfreezeした場合は実行時エラーで上書きは防げるようだ。
この辺の挙動は、型付けが厳密だったり、変数・定数の宣言の仕方に明確な違いがある言語に慣れている場合は、ちょっとルーズに感じて慣れるのに手こずるかもしれない。
「定数なんだから、上書きなんてやろうとしたらコンパイルエラーとか、実行時エラーが起きるからそこで気付くっしょ?」という感覚でいると、気付けずにハマりそうな匂いがする。
Discussion