为什么在将值铲入实例方法调用<<时修改实例属性?



为什么行,restaurant.menu<lt"比萨饼",修改我们餐厅实例的@menu属性?我对它的理解是餐馆。菜单被称为"甜甜圈","蛋糕"。此时,方法调用完成。那么为什么<lt;pizza影响@menu属性?

class Restaurant
def initialize(name)
@name = name
end
def menu
@menu = @menu || ["donuts", "cake"]
end
end
restaurant = Restaurant.new("Mcdonalds")
p restaurant.menu             #["donuts", "cake"]
restaurant.menu << "pizza"    #???    
p restaurant.menu             #["donuts", "cake", "pizza"]>

虽然@red_menace已经回答了根本原因是什么,但我将详细说明这意味着什么。

首先,您需要了解Ruby对象的可变性。在这里你可以找到一些好文章。

基本上,在您的示例中,类的menu实例方法返回对类实例的实例变量@menu的引用,该变量是可变数组(您可以通过引用进行修改(。

如果你真的想让它不可变,你可以冻结变量,也可以按照@Jad的建议克隆它。

在这里,你可以找到关于类似问题的精彩讨论。

在这里,您可以看到一个程序跟踪,在您修改menu方法的返回结果时,您修改了实例变量@menu

require 'pp'
class Restaurant
def initialize(name)
@name = name
end
def menu
@menu = @menu || ["donuts", "cake"]
puts "@menu object_id = #{@menu.object_id}"
@menu
end
end
restaurant = Restaurant.new("Mcdonalds")

p restaurant.menu             #["donuts", "cake"]
pp "object instance variables are #{restaurant.instance_variables}"

restaurant.menu << "pizza"    #???    
p restaurant.menu             #["donuts", "cake", "pizza"]>
p "restaurand.menu.object_id = #{restaurant.menu.object_id}"

这是程序的输出:

$ruby main.rb
@menu object_id = 47245049576960
["donuts", "cake"]
"object instance variables are [:@name, :@menu]"
@menu object_id = 47245049576960
@menu object_id = 47245049576960
["donuts", "cake", "pizza"]
@menu object_id = 47245049576960
"restaurand.menu.object_id = 47245049576960"

正如@red_menace所建议的,可能值得尝试以下内容:

class Restaurant
def initialize(name)
@name = name
@menu = ["donuts", "cake"]
end
def menu
@menu.dup
end
end

最新更新