Rubyの文法(3)変数と有効範囲

ローカル変数とグローバル変数の違い程度は理解しているつもりでしたが、Rubyは奥が深いです。
Rubyの変数は型によって有効範囲(スコープ)が異なっていました。
幾つかの例を挙げながら説明したいと思います。

1.ローカル変数
モジュール内でのみ有効という考え方は当たり前ですが、
ループなどのブロック内でしか有効でないという考え方が他言語ではあるのと比べ
Rubyは少し複雑です。


(1) while, until, forなどの制御構造では有効範囲を作りません。
したがって次のようなコーディングが許されます。

/app/controllers/appli_controller.rb

class AppliController < ApplicationController
def sample
t=[{:week=>0, :name=>"Sunday"},
{:week=>1, :name=>"Monday"},
{:week=>2, :name=>"Tuesday"},
{:week=>3, :name=>"Wednesday"},
{:week=>4, :name=>"Thursday"},
{:week=>5, :name=>"Friday"},
{:week=>6, :name=>"Saturday"}]
i=0
fg="off"
until fg=="ON" do
if t[i][:week]==5 then
find_name=t[i][:name]
fg="ON"
end
i+=1
end
p find_name
end
end


p find_nameの結果は"Friday"です。


(2) each, loopなどのイテレータは有効範囲を作ります。

/app/controllers/appli_controller.rb

class AppliController < ApplicationController
def sample
t=[{:week=>0, :name=>"Sunday"},
{:week=>1, :name=>"Monday"},
{:week=>2, :name=>"Tuesday"},
{:week=>3, :name=>"Wednesday"},
{:week=>4, :name=>"Thursday"},
{:week=>5, :name=>"Friday"},
{:week=>6, :name=>"Saturday"}]
i=0
loop{
if t[i][:week]==5 then
find_name=t[i][:name]
break
end
i+=1
}
p find_name
end
end


p find_nameの結果は
undefined local variable or method `find_name' for #
となります。


(3) 正しく記述しましょう
loopの外側でfind_nmeを定義すれば意図した動作になります。
untilも同様に記述したほうがよいでしょう。

/app/controllers/appli_controller.rb

class AppliController < ApplicationController
def sample
t=[{:week=>0, :name=>"Sunday"},
{:week=>1, :name=>"Monday"},
{:week=>2, :name=>"Tuesday"},
{:week=>3, :name=>"Wednesday"},
{:week=>4, :name=>"Thursday"},
{:week=>5, :name=>"Friday"},
{:week=>6, :name=>"Saturday"}]
i=0
find_name=""
loop{
if t[i][:week]==5 then
find_name=t[i][:name]
break
end
i+=1
}
p find_name
end
end


p find_nameの結果は"Friday"です。


2.インスタンス変数
RailsはMVCモデルにより作られたフレームワークです。
モデルModel、ビューView、コントローラcontrollerと分けて管理します。


(1) まず1から10までの合計を計算するプログラムをビューに書いてみましょう。

/app/controllers/appli_controller.rb

class AppliController < ApplicationController
def compute
end
end

/app/views/compute.html.erb

<%
sum = 0
for i in 1..10
sum += i
end
%>

<p>
1から10までの合計 <%= sum %>
</p>



結果は正しく「1から10までの合計 55」と表示されます。


(2) しかし、これはMVCの書き方に違反しています。
計算部分と表示部分を分けて書いてみます。

/app/controllers/appli_controller.rb

class AppliController < ApplicationController
def compute
sum = 0
for i in 1..10
sum += i
end
end
end

/app/views/compute.html.erb

<p>
1から10までの合計 <%= sum %>
</p>


結果は次の通りです。
undefined local variable or method `sum' for #
これはsumがモジュールをまたがっていてビューでは未定義と判断されるためです。


(3) この受け渡しを有効にするためにインスタンス変数を導入します。

/app/controllers/appli_controller.rb

class AppliController < ApplicationController
def compute
@sum = 0
for i in 1..10
@sum += i
end
end
end

/app/views/compute.html.erb

<p>
1から10までの合計 <%= @sum %>
</p>


結果は正しく「1から10までの合計 55」と表示されます。