【问题标题】:How do I make a class whose constructor looks like the constructor of a built-in class?如何创建一个其构造函数看起来像内置类的构造函数的类?
【发布时间】:2015-03-04 01:32:11
【问题描述】:

Complex 是一个内置类。为了创建一个Complex 对象,我写:

Complex(10, 5)

但如果我创建自己的课程Thing:

class Thing
  def initalize()
  end
end

要创建一个新的Thing,我必须写:

Thing.new(...)

是否可以为Thing 创建一个构造函数以便我可以编写:

Thing(...)

让它像Complex(1,1)这样的内置类一样工作?

【问题讨论】:

  • 那些不是内置类的构造函数,但是......(这是一个提示。)顺便说一句,这些的源是可用的。
  • 为了扩展 Dave 的观点,大写字母后跟括号的不是类,而是方法。
  • Complex 和所有其他“我真的是一个函数,但 Ruby 没有函数”的方法只是 Kernel 中的方法。

标签: ruby constructor


【解决方案1】:

Complex 可以引用Complex class 或内核中定义的Complex method

Object.const_get(:Complex) #=> Complex
Object.method(:Complex)    #=> #<Method: Class(Kernel)#Complex>

后者称为全局方法(或全局函数)。 Ruby 在Kernel 中将这些方法定义为私有实例方法:

Kernel.private_instance_methods.grep /^[A-Z]/
#=> [:Integer, :Float, :String, :Array, :Hash, :Rational, :Complex]

和单例方法:

Kernel.singleton_methods.grep /^[A-Z]/
#=> [:Integer, :Float, :String, :Array, :Hash, :Rational, :Complex]

就像内核中的任何其他方法一样:

这些方法在没有接收者的情况下调用,因此可以以函数形式调用

您可以使用module_function 将自己的全局方法添加到Kernel

class Thing
end

module Kernel
  module_function

  def Thing
    Thing.new
  end
end

Thing          #=> Thing                      <- Thing class
Thing()        #=> #<Thing:0x007f8af4a96ec0>  <- Kernel#Thing
Kernel.Thing() #=> #<Thing:0x007fc111238280>  <- Kernel::Thing

【讨论】:

  • Object 类包含内核模块,尝试p Object.private_instance_methods.grep /^[A-Z]/,因此您的示例最终在 Object 类中创建了一个私有实例方法,这与顶层 def 所做的完全相同,并且输入更少.
  • @7stud 是的,区别很微妙,但是 OP 想知道如何创建像内置方法这样的方法。 Ruby 在Kernel 中定义它们,而不是在Object 中。
  • 请否决投票者发表评论?我的解释是否错误或具有误导性?
【解决方案2】:
class Dog
  def initialize(name)
    @name = name
  end

  def greet
    puts 'hello'
  end
end


def Dog(x)
  Dog.new(x)  #Create a new instance of the Dog class and return it.
end


d = Dog("Rover")
d.greet

--output:--
hello

【讨论】:

  • 酷谢谢!仍然习惯 Ruby,来自 Python 我认为您的示例只会将 Class Dog 替换为 Function Dog - 但当然不会。
  • @quizdog,是的,ruby 要复杂得多。 ruby 中没有全局方法; def 总是某个类的一部分。 def 将自己附加到任何类是当前类。碰巧顶层的当前类是Object。因此,顶级 def 实际上是 Object 类中的(私有)方法。因此,在 Object 类中定义 def 对 Dog 类没有影响。
  • Ruby 将优先处理作为实际常量的常量(它希望以大写字母开头); Dog(x) 仅作为方法调用,因为 Ruby 知道由于传递的参数而正在寻找方法。如果您定义了一个零参数方法Dog,然后尝试在不带括号的情况下调用它,那么您将获得该类。
  • @ChrisHeald,我试图指出 Dog 类与 Dog def 的范围不同,因此 Dog def 不会“替换” Dog 类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-13
  • 1970-01-01
  • 2023-04-03
相关资源
最近更新 更多