为什么可以';我不能从ruby中的类方法调用include吗?

为什么可以';我不能从ruby中的类方法调用include吗?,ruby,Ruby,您可以在ruby中调用include来混入具有类的模块,但必须在类定义的开头进行。为什么不能在类函数中完成?有其他语法吗 例: ^^这是可行的,但如果我将IncludeTester更改为以下内容,则会出现错误“undefined method`include'” 实际上完全可以从类方法中包含模块,如下所示: module Stuff def say_hello puts "hello" end end class Foo def self.i_am_a_class_meth

您可以在ruby中调用include来混入具有类的模块,但必须在类定义的开头进行。为什么不能在类函数中完成?有其他语法吗

例:

^^这是可行的,但如果我将IncludeTester更改为以下内容,则会出现错误“undefined method`include'”


实际上完全可以从类方法中包含模块,如下所示:

module Stuff
  def say_hello
    puts "hello"
  end
end

class Foo
  def self.i_am_a_class_method
    include Stuff
  end

  def i_am_an_instance_method
  end
end

但是,不能从实例方法中执行此操作,因为只能作为私有类方法使用,因此不能从Foo.new实例中访问。

实际上完全可以从类方法中包含模块,如下所示:

module Stuff
  def say_hello
    puts "hello"
  end
end

class Foo
  def self.i_am_a_class_method
    include Stuff
  end

  def i_am_an_instance_method
  end
end
但是,您不能从实例方法执行此操作,因为只能作为私有类方法使用,因此无法从Foo.new实例访问。

是来自模块的方法,模块是类的超类,因此
include
是类上的方法,这使它成为IncludeTester中的类方法。执行此操作时:

class IncludeTester
  def initialize
    include UsefulThings
  end
end
class IncludeTester
  include UsefulThings
end
您试图在一个实例方法中调用一个类方法,Ruby说

`初始化“:未定义的方法“include”

class IncludeTester
  def initialize
    include UsefulThings
  end
end
因为没有名为
include
的实例方法。如果要在实例方法(例如
初始化
)内调用类方法,请执行以下操作:

def initialize
  self.class.include UsefulThings
end
但这是行不通的,因为
include
是一个私有方法;不过,您可以通过以下方式解决此问题:

每次实例化
IncludeTester
时,您都会执行
includeUsefilThings
,除了没有多大意义之外,如果
UsefilThings
有一个方法,它可能会导致问题。

是模块中的一个方法,模块是类的超类,因此
include
是类上的一个方法,这使它成为IncludeTester中的类方法。执行此操作时:

class IncludeTester
  def initialize
    include UsefulThings
  end
end
class IncludeTester
  include UsefulThings
end
您试图在一个实例方法中调用一个类方法,Ruby说

`初始化“:未定义的方法“include”

class IncludeTester
  def initialize
    include UsefulThings
  end
end
因为没有名为
include
的实例方法。如果要在实例方法(例如
初始化
)内调用类方法,请执行以下操作:

def initialize
  self.class.include UsefulThings
end
但这是行不通的,因为
include
是一个私有方法;不过,您可以通过以下方式解决此问题:


每次实例化
IncludeTester
时,您都会执行
includeUsefilThings
,除了没有多大意义之外,如果
UsefilThings
有一个方法,它可能会导致问题。

您想要
扩展
方法:

class IncludeTester
  def initialize
    extend UsefulThings
  end
end
这也不需要在a方法中完成:

IncludeTester.new.tap { |newTester| newTester.extend(UsefulThings) }

您需要
extend
方法:

class IncludeTester
  def initialize
    extend UsefulThings
  end
end
这也不需要在a方法中完成:

IncludeTester.new.tap { |newTester| newTester.extend(UsefulThings) }
它可以在类方法中完成

这项工作:

module UsefulThings
  def a
    puts "a" 
  end
end

class IncludeTester
  def self.mix_in_useful_things
    include UsefulThings
  end 
end

x = IncludeTester.new

IncludeTester.mix_in_useful_things

x.a # => a
但“initialize”不是类方法,而是实例方法

“new”是一个类方法。您可以将new视为分配一个新对象,然后对其调用initialize,将传递给new的参数传递给initialize

不能在initialize中直接调用include,因为include是类的私有方法(从模块继承),而不是新创建的IncludeTester实例的私有方法

如果要从实例方法将模块包含到类中,必须执行以下操作:

class IncludeTester
  def initialize
    self.class.send(:include, UsefulThings)
  end
end
这里有必要使用“send”,因为include是私有方法,这意味着它只能通过隐式接收方(self)直接调用

当您在类定义中正常调用initialize时,实际上是使用“self”的隐式接收器调用它,它指的是正在定义的类

这就是当你这样做时实际发生的情况:

class IncludeTester
  def initialize
    include UsefulThings
  end
end
class IncludeTester
  include UsefulThings
end
它可以在类方法中完成

这项工作:

module UsefulThings
  def a
    puts "a" 
  end
end

class IncludeTester
  def self.mix_in_useful_things
    include UsefulThings
  end 
end

x = IncludeTester.new

IncludeTester.mix_in_useful_things

x.a # => a
但“initialize”不是类方法,而是实例方法

“new”是一个类方法。您可以将new视为分配一个新对象,然后对其调用initialize,将传递给new的参数传递给initialize

不能在initialize中直接调用include,因为include是类的私有方法(从模块继承),而不是新创建的IncludeTester实例的私有方法

如果要从实例方法将模块包含到类中,必须执行以下操作:

class IncludeTester
  def initialize
    self.class.send(:include, UsefulThings)
  end
end
这里有必要使用“send”,因为include是私有方法,这意味着它只能通过隐式接收方(self)直接调用

当您在类定义中正常调用initialize时,实际上是使用“self”的隐式接收器调用它,它指的是正在定义的类

这就是当你这样做时实际发生的情况:

class IncludeTester
  def initialize
    include UsefulThings
  end
end
class IncludeTester
  include UsefulThings
end

是的,这非常有帮助(其他答案也是如此)。是的,这非常有帮助(其他答案也是如此)。差不多!从实例方法调用“extend”不会将模块混合到实例的类中——它会导致将一个不可见的“ghost”类添加到对象继承链的开头(在实际类之前),并将模块混合到该继承链中。像这样混合模块不会影响同一类的其他对象。几乎!从实例方法调用“extend”不会将模块混合到实例的类中——它会导致将一个不可见的“ghost”类添加到对象继承链的开头(在实际类之前),并将模块混合到该继承链中。这样混合模块不会影响同一类的其他对象。绕过私有方法访问保护的惯用方法是使用
send
,而不是任何
eval
方法。绕过私有方法访问保护的惯用方法是使用
send
,不是任何
eval
方法。