2011-08-17 70 views
2

我需要检查一个变量是否是一个数组,如果没有将它转换成一个之后继续进一步处理。所以,我的代码如下所示:奇怪的红宝石行为

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 

我很新的红宝石,所以,这可能还不是很习惯,但对我来说是这样的代码至少应该工作。相反,第二次打印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

实际上,对于您要做的事情,有一个Ruby成语:[*args]*在这种情况下就是所谓的图示操作:

http://raflabs.com/blogs/silence-is-foo/2010/08/07/ruby-idioms-what-is-the-splatunary-operator-useful-for/

如果获得通过一个数组,图示将“扁平化”的阵列到新的一个,如果你传递一个参数,它会成为一个元素数组。

对于奇怪的行为:就像你在你的eval方法,因为它是在一个赋值的LHS其被初始化为nil创建一个局部变量args在我看来。然后三元评估为假,因为args不是一个数组,并产生一个当前值的数组,它仍然是nil。如果args将是一个实例变量(@args),那么事情会按照您的预期工作。换句话说,虽然继承Struct会给你argsargs=方法,但它不会给你一个@args实例变量。

+0

谢谢,我会尝试摔跤运营商。无论如何,我仍然不清楚发生了什么......'args'变量已经被实例化,因为我可以毫无问题地打印它,并且我可以将它重新分配给一个局部变量(工作代码中的'a') 。此外,我尝试在顶层函数中使用相同的代码,并且按预期工作。我的怀疑是“args”被定义为一些访问器方法,那么,我做了一些我并不期待的事情:) – cheng81

+0

是的,'args'是一个访问器方法(正如我的文章的最后一句中提到的那样),所以它在'p“1内工作。#{args}”'。但接下来在下一行中定义一个局部变量,当Ruby尝试解析裸词时,它首先尝试将它们解析为局部变量,而不是方法调用。 –

+0

是的,我感到困惑的看起来像一个变量的访问器方法。那么这意味着,一旦定义,结构中的属性是不可修改的?无论如何,我想通过重载构造函数并简单地调用'super([* args])'来解决。感谢您的照明速度答案,顺便说一句:) – cheng81