地方でリモートワーク

プログラミング、先物、fx,仮想通貨なんでもやります

Ruby Gold勉強メモ(2)

スポンサーリンク

f:id:ihatov08:20160414004338j:plain

束縛

  • ブロックを作成すると、xのようなローカル変数を包み込む
  • メソッドにも束縛が存在する
  • メソッドにあるxではなく、ブロックが定義された時のxを見ている
  • メソッドにある束縛はブロックから見えない
def my_method
  x = 'メソッドの中' # !> assigned but unused variable - x
  yield('メソッドの中のブロック')
end

x = 'メソッドの外'

my_method { |y| "#{x} #{y} どれが出力される?" } # => "メソッドの外 メソッドの中のブロック どれが出力される?"
  • ブロックの中で新しい束縛を定義することもできる
  • しかし、ブロックが終了した時点で消えてしまう
def just_yield
  yield
end

top_level_variable = 1

just_yield do
  top_level_variable += 1
  # ブロックの中でローカル変数を定義する
  # でもブロックの中だけで、外から呼び出すとエラーになる
  local_to_block = 1 # 新しい束縛 # !> assigned but unused variable - local_to_block
end

top_level_variable              # => 2
local_to_block                  # => Error

スコープ

クラス、メソッドがスコープになる

v1 = 1
local_variables                 # =>  [:v1]

class MyClass
  v2 = 2 # !> assigned but unused variable - v2
  local_variables               # => [:v2]
  def my_method
    v3 = 3 # !> assigned but unused variable - v3
    local_variables             # =>  [:v3]
  end
  local_variables               # => [:v2]
end

obj = MyClass.new
obj.my_method                   # => [:v3]
obj.my_method                   # => [:v3]
local_variables                 # => [:v1, :obj]

グローバル変数はどのスコープからもアクセスできる

def a_scope
  $var = 'some value'
end

def another_scope
  $var
end

a_scope                         # => "some value"
another_scope                   # => "some value"
  • グローバル変数の代わりにトップレベルのインスタンス変数を使うこともできる
  • selfになる場所であればどこからでも呼び出せる
@var = 'トップレベルの変数@var'

def my_method
  @var
end

my_method                       # => "トップレベルの変数@var"
  • 他のオブジェクトがselfになれば、トップレベルのインスタンス変数はスコープから外れる
@var = 'トップレベルの変数@var'

def my_method # !> 
  @var
end

my_method                       # => "トップレベルの変数@var"

class MyClass
  def my_method # !> 
    @var = 'トップレベルの変数@varではない'
  end
end

MyClass.new.my_method           # => "トップレベルの変数@varではない"

スコープゲート

v1 = 1 
class MyClass # スコープゲート: classの入口
  v2 = 2
  local_variables               # => [:v2, :_xmp_1497065613_37095_295127]
  def my_method # スコープゲート: defの入口
    v3 = 3 # 
    local_variables
  end # スコープゲート defの出口
  local_variables
end # スコープゲート classの出口

obj = MyClass.new
obj.my_method                   # => [:v3]
local_variables                 # => [:v1, :obj, :_xmp_1497065613_37095_295127]

スコープゲートのフラット化

my_var = '成功'

MyClass = Class.new do
  # これでmy_varを表示できる
  p "クラス定義の中は#{my_var}"

  define_method :my_method do
    "メソッド定義のなかも#{my_var}!"
  end
end

MyClass.new.my_method           # => "メソッド定義のなかも成功!"
# >> "クラス定義の中は成功"

スコープの共有

複数のメソッドで変数を共有したいが、その他からは見えないようにしたいときはフラットスコープを用いる

def define_methods
  shared = 0

  Kernel.send :define_method, :counter do
    shared
  end

  Kernel.send :define_method, :inc do |x|
    shared += x
  end
end

define_methods                  # => :inc
counter                         # => 0
inc(4)                          # => 4
counter                         # => 4

トップレベルのメソッド定義

  • トップレベルにメソッドを定義すると,どのクラスからも呼び出せる
  • 同名のローカル変数を作成した場合、ローカル変数が優先される
def foo
  p 'foo'
end

class MyClass
  foo
end

class MyClass
  foo = 'MyClass foo'
  p foo
end

class MyClass
  foo
end

class MyClass
  foo                           # => "foo"
  def bar
    self.foo
  end
  def foo
    'MyClass foo method'
  end
end
MyClass.new.bar                 # => "MyClass foo method"

# >> "foo"
# >> "MyClass foo"
# >> "foo"
# >> "foo"