这让人有点蛋疼,定义一个类方法,五种途径:
#1
class Person
def self.species
"Homo Sapien"
end
end
#2
class Person
def Person.species
"Homo Sapien"
end
end
#3
class Person
class << self
def species
"Homo Sapien"
end
end
end
#4
class << Person
def species
"Homo Sapien"
end
end
#5
Person.instance_eval do
def species
"Homo Sapien"
end
end
以上引自代码示例引自http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/,略有改动。
定义一个类方法而已,为什么要有这么多种方法存在?
如果再加上一种变态的 class_eval 的示例:
#6
class Foo
end
metaclass = (class << Foo; self; end)
metaclass.class_eval do
def species
"Homo Sapien"
end
end
end
.....那就是 6 种方法了.
而后,这数种方法,在定义方法的范围,self 指代不同的对象,有的指向 Foo 类,有的则指向 Foo 类的 metaclass.有的打开了一个新的 scope(可以调用外面的变量),而有的则不可以.
用 yehada katg 的话来说:'At this point in other articles on this topic, you’re probably struggling to keep all of the details in your head; it seems as though there are so many rules.'
这么多规则让人怎么记它 ! 让人怎么不弄乱它!
一项操作,弄 6 种(可能更多)solution 出来,有必要吗?值得吗?
事实上,有必要的。因为这数种方法虽然在效果上看起来没有区别 (不就是定义了个类方法吗!).但实际上这中间的细微差异 (self 的不同,scope 的不同) 是为不同的要求而特意设计的。比如说,元编程.
这里举个例子:
name = "foo"
var = "bar"
metaclass = (class << String; self; end)
metaclass.class_eval do
define_method(name) do
puts var
end
end
String.foo # bar
这里,因为 class_eval 开了一个新的 scope,所以,可以直接调用之前调用之外的变量 name 与 var.而这样做却是不行的:
name = "foo"
var = "bar"
class Foo
define_method(name) do
puts var
end
end
Foo.foo # bar
这样也不行:
name = "foo"
var = "bar"
class Foo
class << self
define_method(name) do
puts var
end
end
end
Foo.foo # bar
因为class Foo
, class<<Foo
, class Foo;def self.bar;end;end
, 以及class Foo;def Foo.bar;end;end
这几种方式都打开了新的 scope(作用域).直接的结果是,对外部环境的 scope 调用不着。
哪一天你需要这样用元编程,但是不知道如果控制作用域,what are you going to do?定义一个动态存取的实例变量?或者干脆用类变量?
事实上,对这些细节的使用,远远不只元编程这么个例子这么简单。在开发的过程中,你永远不知道下一刻你会遇到多诡异的要求。当然,大部分情况下你可以想出办法来解决这些问题。但是,很多时候,最直接有效的解决办法可能就直接隐藏在这些小细节里。引用乔帮主的一句话:you can't connect the dots looking forward;you can only connect them looking backwards
扯了这么多,只是要分享一点心得:多种途径实现一种方法,并不是给你的大脑加负的。而是为了实现强大的功能而特意设计的.多途径得出的结果,看似效果相同,实际上,却隐藏了许多细微的差别。而这种设计的目的,就是为了让我们能根据不同的需要,利用这些差异更便利地得到自己想要的。
最后,再次推荐一下:http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/
这里面的探讨很深入,有助于大家进一步理解。