代码之家  ›  专栏  ›  技术社区  ›  zzzcats

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

  •  0
  • zzzcats  · 技术社区  · 3 年前

    为什么排队,餐馆。菜单<&书信电报;“披萨”,为我们的餐厅实例修改@menu属性?我的理解是餐馆。菜单被调用并完成对[“甜甜圈”、“蛋糕”]的评估。此时方法调用完成。那么为什么<&书信电报;披萨会影响@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"]>
    
    0 回复  |  直到 3 年前
        1
  •  2
  •   Baurito    3 年前

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

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

    基本上在你的例子中 menu 类的instance方法返回对实例变量的引用 @menu 类的实例,它是可变数组(您可以通过引用修改它)。

    如果你真的想让它不变,你可以 freeze 变量,或者按照 @Jad .

    Here 你可以在类似的问题上找到很好的讨论。

    在这里,你可以看到一个程序跟踪,你一直在修改它 菜单 方法的返回结果,您修改了实例变量 @菜单 .

    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"
    
        2
  •  0
  •   Jad    3 年前

    正如@red_nerge所暗示的,或许值得尝试以下方式:

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