我在ruby中实现BST并使用递归编写插入方法。
我试图使用attr_accessor设置和获取root但它不起作用。任何人都可以帮忙吗?
class Node
attr_accessor :value, :left_child, :right_child
def initialize (value)
@value = value
@left_child = nil
@right_child = nil
end
end
class BST
attr_accessor :root
def initialize
@root = nil
end
def insert(value, node)
if node == nil
node = Node.new(value)
return node
end
return node if node.value == value
if node.value > value
if node.left_child == nil
node.left_child = Node.new(value)
return
else
insert(value, node.left_child)
end
else
if node.right_child == nil
node.right_child = Node.new(value)
return
else
insert(value, node.right_child)
end
end
end
end
mybst = BST.new
p mybst.root
mybst.insert(1, mybst.root)
mybst.insert(2, mybst.root)
mybst.insert(10, mybst.root)
mybst.insert(12, mybst.root)
p mybst
上面的代码显示了Node类的简单实现和带有insert方法的BST类。给我#<BST:0x00557398d02378 @root=nil>
如果我使用self.root它是有效的。
可以使用@root访问根,但是类不应该直接与其实例变量交互。这就是我们需要attr_accessor提供的getter和setter方法的原因。但它不起作用。我错过了什么?
以下是POODR一书的截图。它表示即使在课堂上也不要直接使用实例变量。
在实例方法中使用实例变量实际上是完全可以的。事实上,这就是他们的目的! Setter和getter允许实例外部的东西访问实例内的变量。他们(基本上)为这个类定义实例方法,如下所示:
class Foo
# getter -- Same as attr_reader :root
def root
@root
end
# setter -- Same as attr_writer :root
def root=(root)
@root = root
end
# attr_accessor defines a setter *and* a getter.
end
所以,你可以通过定义#insert
来简化你的代码,这样它只需要一个参数(value
)并用引用node
替换你引用@root
的每个地方。
我认为你正在寻找的方式(但不是“正确的”方式,我不建议)是调用访问者定义的root
和root=
方法。
如果你采用这条路线,你还必须定义#insert
只将value
作为参数,并用node
替换你引用root
的每个地方。这样可行,但这不是解决问题的正确方法。如果你这样解决,请在CodeReview.se上提问,这样我就可以澄清如何使代码更好。
在#insert方法中,您正在操作传递给方法的node
参数,而不是root
。 Ruby是通过值传递而不是通过引用传递(sorta),所以当你将mybst.root
传递给#insert
时,你实际上是在传递nil
,因为mybst.root == nil
。然后mybst.insert
调用返回一个新的Node,但是你没有对该返回值做任何事情。如果你想将root
设置为该返回值,你可以这样做:
mybst = BST.new
p mybst.root
mybst.root = mybst.insert(1, mybst.root)
mybst.root = mybst.insert(2, mybst.root)
mybst.root = mybst.insert(10, mybst.root)
mybst.root = mybst.insert(12, mybst.root)
p mybst
我认为这里令人困惑的部分是教科书所说的:
隐藏变量,甚至可以从定义变量的类中隐藏变量
这是正确的,但我认为你误解了它。本节说您应该隐藏该实例之外的任何实例变量。在该实例中,使用它们是完全可以的,这实际上是实例变量存在的原因 - 在实例中存储状态。定义行为方法而不是直接暴露实例变量只是更好。当然,这只是一个要记住的规则 - 我确信你会遇到这种建议不适用的情况,但通常你想要将实例变量保持在内部。