请不要问我“你为什么要这样做?”我只是在探索 Ruby 的角落和缝隙,没有特定的目标。
一些 Ruby 类可以仅使用括号进行实例化,而不是显式调用
#new
方法。例如,
irb> require 'pathname'
irb> p=Pathname('/etc/xdg/autostart')
=> #<Pathname:/etc/xdg/autostart>
irb> n=Pathname.new('/etc/xdg/autostart')
=> #<Pathname:/etc/xdg/autostart>
irb> p==n
=> true
有些人用它来强制转换/强制,如
Integer(4.5)
所示。可能还有其他用途我还没有遇到过,或者记不清了。
但是,我还没有找到一种方法来为自定义类执行此操作:
irb> class Foo ; def initialize(*args) ; @args=args ; end ; end
=> :initialize
irb> f1=Foo.new(1,2,3)
=> #<Foo:0x00007f330a29f4e8 @args=[1, 2, 3]>
irb> fp=Foo(1,2,3)
(irb):7:in `<main>': undefined method `Foo' for main:Object (NoMethodError)
Did you mean? for
我唯一能弄清楚的是
Pathname
和Integer
(例如)都使用C代码,并且以某种方式最终成为内核方法:
irb> Object.method(:Pathname)
=> #<Method: #<Class:Object>(Kernel)#Pathname(_)>
irb> Object.method(:Integer)
=> #<Method: #<Class:Object>(Kernel)#Integer(*)>
irb> Object.method(:Foo)
(irb):10:in `method': undefined method `Foo' for class `#<Class:Object>' (NameError)
Did you mean? for
所以这似乎是由 C/
.so
扩展代码提供的。
但是,是否可以简单地使用本机 Ruby 代码来完成,而不需要像下面这样的拼凑?
irb> Object.define_method(:Foo) { |*args| Foo.new(*args) }
=> :Foo
irb> Foo(1,2,3)
=> #<Foo:0x00007f330a3b9018 @args=[1, 2, 3]>
这些全局方法是在
Kernel
中定义的所谓模块函数。您可以这样定义自己的全局函数:
module Kernel
def Foo(...) = Foo.new(...)
module_function :Foo
end
上面定义了一个方法
Kernel#Foo
,它将所有参数委托给Foo.new
。 module_function
使该方法可用作类方法:
Foo(1, 2, 3) #=> #<Foo:0x000000010633e120 @args=[1, 2, 3]>
它还将实例方法标记为 private:
:hello.Foo(1, 2, 3) # NoMethodError: private method `Foo' called for an instance of Symbol
这就是
Integer
、Pathname
等的行为方式。