假设你有User
课程:
class User
attr_accessor :widgets
end
和Widget
:
class Widget
attr_accessor :owner
end
并为用户分配一些小部件:
user = User.new
widget = Widget.new
widget.owner = user
widget2 = Widget.new
widget2.owner = user
user.widgets = [widget, widget2]
现在您的递归为user
→widgets
→owner
。 user.inspect
为每个小部件显示相同的user
引用,使输出变得混乱:
user.widgets.first.owner.widgets.first.owner
=> #<User:0x00000001cac820 @widgets=[#<Widget:0x00000001ca45f8 @owner=#<User:0x00000001cac820 ...>>, #<Widget:0x00000001c87a20 @owner=#<User:0x00000001cac820 ...>>]>
如果我们要将此数据结构减少为哈希,我们将拥有:
{ user:
{ widgets: [ { widget: ... },
{ widget: ... } ]
}
}
我们可以传递此内容而不是分配widget.owner
,并且引用父user
很容易。
我想知道是否有办法通过子进程访问父对象,而不必将owner
分配给所有子对象,这个界面可以像这样工作:
user = User.new
widget = Widget.new
user.widgets = [widget]
widget.parent
# => #<User:... @widgets=[#<Widget:...>]>
答案 0 :(得分:1)
您正在寻找的是自定义作家。 parent
或Object
类上没有BaseObject
方法或等效方法,因为实现该方法需要对象跟踪碰巧指向它的每个其他对象。但是,当您需要该功能时,自定义编写器可以使其简单易用。
class Widget
attr_accessor :owner
end
class User
attr_reader :widgets
def widgets=(widgets)
@widgets = widgets
widgets.each do |widget|
widget.owner = self
end
end
end
user = User.new
widget = Widget.new
user.widgets = [widget]
widget.owner #=> #<User:... @widgets=[#<Widget:...>]>
请注意,此自定义编写器仅涵盖常规分配,例如user.widgets = [widget]
。如果您想执行user.widgets << widget
之类的操作,则不会为新窗口小部件分配所有者。如果您希望能够这样做,则必须monkeypatch Array
like this(不推荐),否则您必须创建可能继承自WidgetCollection
的{{1}}类。这就是ActiveRecord::Associations的作用。说到这一点,如果您碰巧使用Rails,请务必使用ActiveRecord为您完成所有这些操作。看起来你问的是普通的红宝石,所以我给你一个香草红宝石的答案。
答案 1 :(得分:1)
想到分享我已经提出的解释。它没有可靠的证据,但可能有所帮助。
首先,像这样的循环链接对象没有任何问题。如果循环链出现问题,代码将无法正常工作,它会崩溃或显示错误。所以它可能在某种程度上处理这种循环引用,但如果您理解变量只是对象的引用,那么它确实有意义。
我的意思是当您只是访问用户实例user
时,它并不是只是递归地加载其中的所有内容。它什么都不做,或者只是取出参考。真正建立递归的是inspect
方法,它以递归方式检查实例中的所有实例变量。但它确实使用....
来处理深入的检查。
所以你真正的问题应该只是让检查看起来紧凑。您可以覆盖该方法,以便它不会递归,并为您提供一个好消息。示例:
class User
attr_accessor :widgets
def initialize
@widgets =[]
end
def inspect
"[User:objid=#{object_id};widgets=#{widgets.size}]"
end
end
class Widget
attr_accessor :owner
def inspect
"#[Widget:objid=#{object_id}]"
end
end
界面可以保持不变。
user = User.new
widget = Widget.new
widget.owner = user
widget2 = Widget.new
widget2.owner = user
user.widgets = [widget, widget2]
user.widgets.first.owner.widgets.first.owner
# => #[User:objid=-590412418;widgets=2]