ruby 块与局部变量绑定的思考

文章已经修改,之前的结论有误,现已经修改

# =============================
# 重要结论:
# 1、块绑定局部变量的时间:在块被定义的时开始绑定的,绑定局部变量只是名子绑定,块内绑定的同名局部变量的值还可以在块外被修改
#(在块绑定局部变量后,如果块外部的同名局部变量改变了其值,则块中绑定的同名变量的值会被改变)
# 以下测试的局部绑定都证明了绑定是从块被定义时开始的
# 2、注意那些在块中初始化的变量,是否这些变量也出现在块定义外部的前后,不同位置的同名局部变量会对块内的变量产生不同的影响
# =============================

# =============================
# 目标1:
# 测试方法中的局部变量firstname,lastname是否会影响到块中的被绑定的同名变量的值
# =============================
# 结论
# 1、块会绑定局部变量firstname,lastname,把它们以块的方式传到my_method方法
# 它们的值不会受到方法中同名变量的影响(闭包特性)
# =============================
lambda {
  def my_method
    firstname = "Maria"
    lastname = "Sharapova"
    yield "Hi! I'm"
  end
  firstname = "Max"
  lastname = "Black"
  myname = lambda { |say| puts "test1: #{say} #{firstname} #{lastname}" }
  my_method &myname #=> Hi! I'm Max Black
}.call

# <!-- more -->

# =============================
# 目标2:
# 1、测试块可以绑定局部变量的范围
# 2、在块后面出现的局部变量是否会覆盖其块内已经绑定的同名局部变量的值(块中已经绑定的局部变量的值是否会被改变)
# =============================
# 结论
# 1、块会绑定在它定义时出现在它前面的局部变量firstname,lastname.
# 2、块中last变量的值为lastname="wang",因为块在定义时绑定了lastname,块中同名的lastname对上下文中的其它成员
# 是可见的,所以对局部变量赋值lastname="Wang",也就改变了块内lastname的值。它覆盖了前面lastname="Black"的值。
# 3、局部变量lastname="Green"出现在块被调用以后,块调用在赋值语句之前执行,对lastname="Green"的赋值不会影响到
# 块内部的同名变量lastname,此时块内部的lastname="wang"
# =============================
lambda {
  def my_method
    firstname = "Maria"
    lastname = "Sharapova"
    yield "Hi! I'm"
  end
  firstname = "Max"
  lastname = "Black"
  myname = lambda { |say| puts "test2: #{say} #{firstname} #{lastname}" }
  lastname = "Wang"
  my_method &myname #=> Hi! I'm Max Wang
  lastname = "Green"
}.call

# =============================
# 目标3:
# 测试在块中定义的已经初始化的变量的值是否受外部的同名局部变量值的影响:(局部变量的定义在块定义的前面)
# =============================
# 结论
# 1、局部变量不能影响块中同名变量的值
# 2、局部变量的值会随块中同名变量的值在执行过程中的改变而改变,day_changed的值为被改变的值:Mon
# 3、发生1、2情况的原因是,在块被执行时,它会先看到块内的say="Mon",而不再去看被绑定的局部变量say的值("Sun")
# 因为局部变量day已经被绑定到块,块中的day对其上下文可见,在块执行后,块中同名变量day的值会改变局部
# 变量day的值,此时局部变量day的值为"Mon"
# =============================
lambda {
  def my_method
    firstname = "Maria"
    lastname = "Sharapova"
    yield "Hi! I'm"
  end
  firstname = "Max"
  lastname = "Black"
  day = "Sun"
  myname = lambda { |say| day = "Mon"; puts "test3: #{say} #{firstname} #{lastname} at #{day}"}
  #day = "Sun"
  my_method &myname #=> Hi! I'm Max Black at Mon
  day_changed = day
  puts "test3: day:#{day_changed}"
  # day = "Wed"
  # my_method &myname #=> Hi! I'm Max Black at Mon
  # day_changed = day
  # puts "test3: day:#{day_changed}"
}.call

# =============================
# 目标4:
# 测试在块中定义的已经初始化的变量的值是否受外部的同名局部变量值的影响:(局部变量的定义在块定义的后面)
# =============================
# 结论
# 1、最终的值是块中变量的值,局部变量不能影响块中同名变量的值
# 2、局部变量的值会不随块中同名变量的值在执行过程中的改变而改变,day_changed的值:Sun
# 3、发生1、2情况的原因是:因为day局部变量的定义出现在块定义的后面,这就导致了块根本没有绑定day这个局部变量
# 块内的变量day是块内部附加的变量,此时块内部的day与块外部的day没有任何关系
# =============================
lambda {
  def my_method
    firstname = "Maria"
    lastname = "Sharapova"
    yield "Hi! I'm"
  end
  firstname = "Max"
  lastname = "Black"
  # day = "Sun"
  myname = lambda { |say| day = "Mon"; puts "test4: #{say} #{firstname} #{lastname} at #{day}"}
  day = "Sun"
  my_method &myname #=> Hi! I'm Max Black at Mon
  day_changed = day
  puts "test4: day:#{day_changed}"
  # day = "Wed"
  # my_method &myname #=> Hi! I'm Max Black at Mon
  # day_changed = day
  # puts "test5: day:#{day_changed}" # => Web
}.call