3

我知道还有其他关于语法的问题class << self。尽管如此,我还没有发现这些答案足够清楚。我有 Java/C#、C 的背景,所以 Ruby 对我来说有点奇怪。我读到的是class << self指单例类。我觉得这有点复杂,所以我想了解操作员<<在这种情况下做了什么,以及两端都有什么可能。我尝试编写一个简单的代码来帮助我理解这种语法(我的问题在代码中):

class Self

def Self.selfTest
end

def onSelf
    class << Self   #I know this might be strange. 
        self
    end

end

def onself
    class << self
        self
    end
end

end

s = Self.new
onSelf = s.onSelf
onself = s.onself

#Here, i wanna know what kind of references are returned. 

puts "onSelf responds to onSelf:#{onSelf.respond_to?(:onSelf)}"
puts "onSelf responds to selfTest:#{onSelf.respond_to?(:selfTest)}"
puts "onself responds to onSelf:#{onself.respond_to?(:onSelf)}"
puts "onself responds to selfTest:#{onself.respond_to?(:selfTest)}"

#Output:
#onSelf responds to onSelf:false
#onSelf responds to selfTest:false
#onself responds to onSelf:false
#onself responds to selfTest:true

#So, i conclude that the second one is a reference to a class. What is the first one???????


puts onSelf
puts onself

#Output
#<Class:Self>
#<Class:#<Self:0x007f93640509e8>>

#What does this outputs mean???????

def onSelf.SelfMet
    puts 'This is a method defined on base class'
end


def onself.selfMet
    puts 'This is a method defined on metaclass'
end



puts "Does Self Class respond to SelfMet? : #{Self.respond_to?(:SelfMet)}"
puts "Does Self Class respond to selfMet? : #{Self.respond_to?(:selfMet)}"
puts "Does Self instance respond to SelfMet? : #{s.respond_to?(:SelfMet)}"
puts "Does Self instance respond to selfMet? : #{s.respond_to?(:selfMet)}"

#Output
#Does Self Class respond to SelfMet? : false
#Does Self Class respond to selfMet? : false
#Does Self instance respond to SelfMet? : false
#Does Self instance respond to selfMet? : false

#Why won't they respond to defined methods???? 

谢谢

更新: 非常感谢大家。我已经阅读和测试了很多,所以会留下一些注意事项。我将其留作将来参考,因此,如果我错了,我希望 Ruby 专家能纠正我。我意识到 class << Self 指的是 Self 单例类。因此,惯用类 << abcd 启动 abcd 单例类上下文。我还意识到类单例类的层次结构与对象单例类不同。类单例类的层次结构遵循层次结构中的所有单例类。在这种情况下:

单例自身->单例对象->单例基本对象->类->模块->对象->内核->基本对象

对象单例类位于不同的层次结构中:

对象单例->自我->对象->内核->基本对象

这解释了这个输出。

4

2 回答 2

4

在 Ruby 中,每个对象都有一个单例类。这个单例类只有一个实例:它所属的对象。

由于单例类只有一个实例,并且每个对象都有自己的单例类,因此在此类中定义的方法只能在特定对象上调用。这些方法通常称为单例方法,尽管这是一种误导:这些方法没有什么特别之处,它们只是普通的标准实例方法。

这是一个例子:

foo, bar, baz = Object.new, Object.new, Object.new

class << foo; def quux; :foo end end
class << bar; def quux; :bar end end

foo.quux # => :foo
bar.quux # => :bar
baz.quux # NoMethodError

类就像任何其他对象一样只是对象。因此,就像任何其他对象一样,它们具有单例类。在恰好是类的对象的单例类中定义的方法通常称为类方法,尽管它们也没有什么特别之处,它们只是恰好是类的对象的单例方法,这反过来意味着它们只是属于一个恰好是一个类的对象的单例类的常规实例方法。

因此,如果将其与 Java 之类的东西进行比较,您会看到一个二元性:在 Java 中,只有一种类,但有两种方法(实例和静态)。在 Ruby 中,只有一种方法(实例),但它可以定义在不同类型的类(常规和单例)中。

我觉得这有点复杂,所以我想了解运算符 << 在这种情况下做了什么

这只是打开单例类而不是打开类的语法。

以及可以放在两端的东西。

好吧,左边必须是关键字class,右边必须是返回对象的任何表达式。

于 2014-02-08T05:33:13.260 回答
2

也许这会有所帮助。如果添加以下语句,您将获得指示的结果:

puts onSelf                         #=> #<Class:Self> 
puts Self.singleton_class           #=> #<Class:Self>
puts onSelf == Self.singleton_class #=> true

puts onself                         #=> #<Class:#<Self:0x007fe6330aab10>>
puts s.singleton_class              #=> #<Class:#<Self:0x007fe6330aab10>>
puts onself == s.singleton_class    #=> true

我认为定义接收器是元类的方法没有意义,但这就是您所做的:

puts onSelf.SelfMet
  #=> This is a method defined on Self's metaclass

puts onself.selfMet
  #=> This is a method defined on s's metaclass

显然,onSelfSelf.singleton_class)响应SelfMet(但不响应selfmet),并且onselfs.singleton_class)响应selfmet(但不响应Selfmet)。

为了Self响应SelfMet,必须定义后者def Self.SelfMet...def self.SelfMet..(或其他几种方式之一),但事实并非如此。

类似地,为了s响应selfMet,后者必须定义为普通实例方法def selfMet...(在这种情况下,所有其他实例Self也会响应它)或在s的单例类中定义:(def s.selfMet...在这种情况下,Self 的其他实例将不回应)。

总之,类Self响应它的单例方法,就像实例s响应它的单例方法一样;的单例类Self并且s不响应那些各自的单例方法。

以下内容可能会帮助您了解这里发生了什么。每个p self后跟#=>显示#=>当语句由 Ruby 执行时接下来的内容。请注意各种语句(例如class Dogclass << self其他语句)如何用于将 的值更改为self我们想要的值。 p self元编程时是你最好的朋友。

p self            #=> main

class Dog
  p self          #=> Dog

  def self.woof1
    p self
  end

  def Dog.woof2
    p self
  end

  p self          #=> Dog

  class << self
    p self                #=> #<Class:Dog>
    p Dog.singleton_class #=> #<Class:Dog>  
    def woof3
      p self
    end
  end

  p self          #=> Dog

  def woof4
    p self
  end
end

p self            #=> main

def Dog.woof5
  p self
end

Dog.instance_eval do
  p self          #=> Dog
  def woof6
    p self
  end
end  

dog = Dog.new     #=> #<Dog:0x007fe17b08cf00> 

def dog.woof7
  p self
end

dog.instance_eval do
  p self          #=> #<Dog:0x007fe17b08cf00>
  def woof8
    p self
  end
end  

p self            #=> main

Dog.woof1 #=> Dog
Dog.woof2 #=> Dog
Dog.woof3 #=> Dog
Dog.woof5 #=> Dog
Dog.woof6 #=> Dog

dog.woof4 #=> #<Dog:0x007fe17b08cf00>
dog.woof7 #=> #<Dog:0x007fe17b08cf00>
dog.woof8 #=> #<Dog:0x007fe17b08cf00>

puppy = Dog.new #=> #<Dog:0x007fe17ba93a08>
puppy.woof4     #=> #<Dog:0x007fe17ba93a08>
puppy.woof7 #=> undefined method `woof7' for #<Dog:0x007fe5fb3e1d48>
puppy.woof8 #=> undefined method `woof8' for #<Dog:0x007fe5fb3e1d48>

整理一切需要一段时间。即便如此,我们大多数人还是需要不时复习。这是一篇关于这个主题的优秀文章。另外,请查看评论中的一些参考资料,尤其是 Dave Thomas 的演示文稿。

最后,看看 Ruby 的命名约定

于 2014-02-08T01:44:52.220 回答