提问人:cheng81 提问时间:8/17/2011 更新时间:8/17/2011 访问量:231
奇怪的 Ruby 行为
Oddly Ruby behavior
问:
我需要检查变量是否为数组,如果不是,则将其转换为数组,然后再进行进一步处理。所以,我的代码看起来像这样:
class Test < Struct.new(:args)
def eval
p "1. #{args}"
args = (args.instance_of? Array) ? args : [args]
p "2. #{args}" # woah! [nil]?
# ...other things, with "args" being an array for sure..or not?!?
end
end
我对 ruby 很陌生,所以也许这不是很惯用,但对我来说,这段代码至少应该有效。相反,我第二次打印变量时,它是 .
请注意,如果我稍微更改方法:args
[nil]
eval
def eval
p "1. #{args}"
a = args
args = (a.instance_of? Array) ? a : [a]
p "2. #{args}"
end
一切都按预期进行。那么,Struct 类是否有一些非常具体的东西我不明白,或者这里发生了一些可疑的事情? (在 macOSX 上使用 Ruby 1.9.3-dev,使用 RVM)
答:
2赞
Michael Kohl
8/17/2011
#1
实际上,对于您要做的事情,有一个 Ruby 习语:. 在此上下文中称为 SPlat 运算符:[*args]
*
如果你被传递了一个数组,splat 会将数组“扁平化”到新数组中,如果你传递一个参数,它将成为一个单元素数组。
对于奇怪的行为:在我看来,您在方法中创建了一个局部变量,该变量被初始化为因为它位于赋值的 LHS 上。然后三元的计算结果为 false,因为不是一个数组,并组成一个当前值的数组,该数组仍然是 。如果是实例变量 (),则事情将按照您期望的方式工作。换句话说,虽然继承自 will 给你和方法,但它不会给你一个实例变量。args
eval
nil
args
nil
args
@args
Struct
args
args=
@args
评论
0赞
cheng81
8/17/2011
谢谢,我会尝试 splat 运算符。无论如何,我仍然不清楚发生了什么。该变量已经实例化,因为我可以毫无问题地打印它,并且可以将其重新分配给局部变量(在工作代码中)。此外,我尝试在顶级函数中使用相同的代码,它按预期工作。我的怀疑是“args”被定义为一些访问器方法,这些方法可以做一些我不希望:)args
a
0赞
Michael Kohl
8/17/2011
是的,是一种访问器方法(如我帖子的最后一句话所述),因此它可以在里面工作。但是在下一行中,你定义了一个局部变量,当 Ruby 尝试解析裸词时,它首先尝试将它们解析为局部变量,而不是方法调用。args
p "1. #{args}"
0赞
cheng81
8/17/2011
是的,我对看起来像变量的访问器方法感到困惑。所以这意味着,一旦定义,结构中的属性是不可修改的?无论如何,我想我通过重载构造函数并简单地调用 .感谢您的闪电般的答案,顺便说一句,:)super([*args])
0赞
Michael Kohl
8/17/2011
它不是一成不变的,你有.您的问题是您使用局部变量“隐藏”了访问器。无论如何,很高兴你让它工作:-)args=
评论