定数
定義
アルファベット大文字 ([A-Z]) で始まる識別子は定数です。
実験その1
実行結果
[27] pry(main)> HOGE = 'hoge'
=> "hoge"
[28] pry(main)> HOGE = "foo"
(pry):28: warning: already initialized constant HOGE
(pry):27: warning: previous definition of HOGE was here
=> "foo"
[29] pry(main)> HOGE
=> "foo"
結論
一度定義された定数に再び代入を行おうとすると警告メッセージが出ます。代入することは成功になります。
実験その2
実行結果
[30] pry(main)> HOGE = 'hoge'
(pry):30: warning: already initialized constant HOGE
(pry):28: warning: previous definition of HOGE was here
=> "hoge"
[31] pry(main)> HOGE.gsub!('h', 'f')
=> "foge"
[32] pry(main)> HOGE
=> "foge"
結論
破壊的なメソッドを呼び出すと警告メッセージが出せずに成功になりました。
freeze
定義
オブジェクトを凍結(内容の変更を禁止)します。
実験その1
実行結果
[34] pry(main)> hoge = 'hoge'.freeze
=> "hoge"
[35] pry(main)> hoge = 'foo'
=> "foo"
[36] pry(main)> hoge
=> "foo"
結論
一度凍結された文字列の変数に再び代入を行おうとすると警告メッセージが出せずに成功になりました。
実験その2
実行結果
[37] pry(main)> hoge = 'hoge'.freeze
=> "hoge"
[38] pry(main)> hoge.gsub!('h', 'f')
RuntimeError: can't modify frozen String
from (pry):38:in `gsub!'
[39] pry(main)> hoge
=> "hoge"
結論
破壊的なメソッドを呼び出すとエラーになりました。
組み合わせると
実験その1
実行結果
irb(main):001:0> HOGE = 'hoge'.freeze
=> "hoge"
irb(main):002:0> HOGE = 'foo'
(irb):2: warning: already initialized constant HOGE
(irb):1: warning: previous definition of HOGE was here
=> "foo"
irb(main):003:0> HOGE
=> "foo"
結論
定数と同じく、一度定義された定数に再び代入を行おうとすると警告メッセージが出ます。代入することは成功になります。
実験その2
実行結果
irb(main):001:0> HOGE = 'hoge'.freeze
=> "hoge"
irb(main):002:0> HOGE.gsub!('h', 'f')
RuntimeError: can't modify frozen String
from (irb):2:in `gsub!'
from (irb):2
from /Users/longlong.li/.rbenv/versions/2.3.0/bin/irb:11:in `<main>'
irb(main):003:0> HOGE
=> "hoge"
結論
freezeと同じく、破壊的なメソッドを呼び出すとエラーになりました。
まとめ
rubyはパフォーマンスが良くないという指摘がよくあると思うけど、普段の実装でさらにコードのパフォーマンスを注意しなければいけない。
ref:
https://www.educba.com/javascript-vs-ruby/
https://www.techmagic.co/blog/nodejs-vs-ruby-on-rails/
定数のメリット
irb(main):001:0> HOGE = 'hoge'
=> "hoge"
irb(main):002:0> HOGE.object_id
=> 70133661978580
irb(main):003:0> 'hoge'.object_id
=> 70133661959980
irb(main):004:0> 'hoge'.object_id
=> 70133579010700
irb(main):005:0> HOGE.object_id
=> 70133661978580
irb(main):006:0> HOGE.object_id
=> 70133661978580
文字列を何回呼び出すと新しいアドレスにスペースを開けてobjectを作ります。
定数の場合は、同じアドレスの値を参照する。変数の場合も同じ。
freezeのメリット
定数を定義された場合は、再び代入する際はwarnningがあるけど、破壊的なメソッドを呼び出したら、何の提示出て来ない。定数を固定するためにfreezeで強制的に文字列を凍結した方がいいと思います。
irb(main):001:0> HOGE = 'hoge'.freeze
=> "hoge"
irb(main):002:0> HOGE.object_id
=> 70152318756020
irb(main):003:0> HOGE.gsub!('h', 'f')
RuntimeError: can't modify frozen String
from (irb):3:in `gsub!'
from (irb):3
from /Users/longlong.li/.rbenv/versions/2.3.0/bin/irb:11:in `<main>'
irb(main):004:0> HOGE.object_id
=> 70152318756020
irb(main):005:0> HOGE = 'hoge'.freeze
(irb):5: warning: already initialized constant HOGE
(irb):1: warning: previous definition of HOGE was here
=> "hoge"
irb(main):006:0> HOGE.object_id
=> 70152318756020
Tips
Ruby 2.x. から下記の一行をファィルの頭で記入すると、静的な文字列は自動的に凍結されます。
# frozen_string_literal: true
都度.freeze
を追加する必要はなくなって、結構便利です。