Ruby 类构造函数使用 `()` 而不是 `.new()`

问题描述 投票:0回答:1

不要问我“你为什么要这样做?”我只是在探索 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]>
ruby oop constructor
1个回答
0
投票

这些全局方法是在

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
等的行为方式。

© www.soinside.com 2019 - 2024. All rights reserved.