4

我知道有“实例方法”、“类方法”,但是这些类型的方法称为什么,例如:

s1 = "This is my STRING!"

def s1.m1
  downcase
end

p s1     # => "This is my STRING!"
p s1.m1   # => "this is my string!"

在“string”类的 s1“instance”上调用的“m1”方法是什么类型的方法?这真的很奇怪,因为如果我尝试,我根本不知道这是可能的:

s2 = "This is ANOTHER string"
s2.m1 # => Won't work!

哪种有意义,但不确定为什么在类的实例上定义像 m1 这样的方法是有用的。

4

4 回答 4

4

它们被称为单例方法,可以定义如下:

class Person
  def favorite_meal
    "Big Mac"
  end
end

Fred, Joe = 2.times.map { Person.new }

def Fred.favorite_meal
  "Le Big Mac"
end

Joe.favorite_meal #=> Big Mac
Fred.favorite_meal #=> Le Big Mac

定义相同单例方法的其他方法是:

Fred.define_singleton_method :favorite_meal do "Le Big Mac" end

和:

class << Fred
  def favorite_meal
    "Le Big Mac"
  end
end

愿原力与你同在。


更新:回答评论中的两个问题。

让我从第二个开始。使用常量还是变量取决于您。写起来完全没问题fred = Person.new。但:

  1. 具有不同属性的对象通常应该得到正确的名称,并正确大写。

  2. 我写了一个有用的 gem y_support/name_magic,它通过分配给常量来工作。

通过 安装它gem install y_support,然后尝试:

require 'y_support/name_magic'

class Dog
  include NameMagic
  def speak; puts "Bow wow!" end
end

Spot, Rover = 2.times.map { Dog.new }

现在Dog类知道它的实例,实例也知道它们的名字。

Dog.instances.map { |dog| dog.name } #=> :Spot, :Rover
Dog.instances.names # the simpler way to say the same

这在这个特定示例中没有用(在其他地方非常有用),但无论如何,它让我养成了给具有个性的对象以大写专有名称的习惯。

至于第一个问题,def Fred.foobar是最基本的,一次性的单例方法定义。如果要定义多个单例方法或别名,或在单例类中包含一个模块,请使用class << Fred

module Foo
  def bar; "Fretbar!" end
end

class << Fred
  include Foo
  alias le_favorite favorite_meal
end

Fred.bar #=> Fretbar!
Fred.le_favorite #=> "Le Big Mac"

最高级的事情可以通过Fred.define_singleton_method语法和第 4 种方式实现,我之前没有提到:

local_var = 42

Fred.singleton_class.class_exec do
  define_method :baz do local_var + 1 end
end

Fred.baz #=> 43

这种方式使用闭包,它保留对变量的绑定local_var。试试看

local_var = 32
Fred.baz #=> 33

所以这就是闭包语法的特别之处,它通常是神奇地解决令人讨厌的编程问题的天赐之物。

于 2013-11-03T16:29:50.483 回答
2

它们被称为对象Singleton Methods

example我能想到你可以在哪里使用它:

您有一个特殊的日志记录类,您必须将日志记录限制为仅一个实例,因为您希望日志记录文件干净整洁。

也许不是最好的例子,但如果您对用例感兴趣,请查找用例,Singleton Pattern您应该在那里找到答案。

于 2013-11-03T15:57:36.700 回答
1

它们被称为单例方法。这是检查这些的一些方法:

s1 = "This is my STRING!"

def s1.m1
  downcase
end

klass= s1.singleton_class # => #<Class:#<String:0x902d4e8>>
klass.instance_methods(false) # => [:m1]
s1.method(:m1).owner # => #<Class:#<String:0x902d4e8>>
s1.singleton_methods # => [:m1]

但不确定为什么在类的实例上定义像 m1 这样的方法是有用的。

这些单例方法(m1)只能由 调用s1,正如您在 的单例类中定义的那样s1。但不是由String该类的任何其他实例。当您有一些对象独有的行为时,这些是需要的,无论它们属于同一类还是不同类。

s2.m1 # => 不行!

因为您没有在s1.

于 2013-11-03T16:10:00.657 回答
0

“(...)但不确定为什么在类的实例上定义像 m1 这样的方法是有用的。”

它使这种行为成为可能:

class Test
  def self.some_meth
  end
end

test 只是 Class 的一个实例,并且 some_method 被添加到这个特定的实例中。

p Test.singleton_methods #=> [:some_meth]
于 2013-11-03T17:28:41.317 回答