全局符号上下文中的类与实例方法

时间:2017-04-11 21:39:36

标签: ruby class oop global symbols

我正在通过Service Objects阅读关于Dave Copeland的博文,并发现了以下内容:

  

Ruby中的类是全局符号,这意味着类方法是全局符号。编码为全局变量是我们不再使用PHP的原因。

我想更多地理解这个陈述并提出一些问题。

  • 类方法和实例方法在符号上下文中有何不同?

例如,参加以下irb会话:

irb(main):001:0> Symbol.all_symbols.grep /Foo/
=> []
irb(main):002:0> Symbol.all_symbols.grep /some.*method/
=> []
irb(main):003:0> class Foo
irb(main):004:1> def some_instance_method; end
irb(main):005:1> def self.some_class_method; end
irb(main):006:1> end
=> :some_class_method
irb(main):007:0> Symbol.all_symbols.grep /Foo/
=> [:Foo]
irb(main):008:0> Symbol.all_symbols.grep /some.*method/
=> [:some_instance_method, :some_class_method]
  • #some_instance_method::some_class_method在符号上下文中有何不同?
  • 当我检查Symbol.all_symbols时,我在做什么,这与查看"全局符号"?
  • 相同
  • 为什么显示#some_instance_method::some_class_method?在阅读了上述引用后,我预计008的结果为:

    IRB(主):008:0> Symbol.all_symbols.grep /some.*method/ => [:some_instance_method]

3 个答案:

答案 0 :(得分:1)

我认为Dave对他所说的方式有点不清楚,但他解释了你摘录后段落中的影响:

  

服务作为全球符号存在问题的一个很好的例子是Resque。所有Resque方法都可以通过Resque获得,这意味着任何Ruby VM都只有一个可以使用的resque。

     

[...]

     

另一方面,如果将Resque实现为一个对象而不是全局,那么任何需要访问不同Resque实例的代码都不必更改 - 它只会被赋予一个不同的对象。

不同之处在于界面:使用Resque,工具的用户“依赖”并与特定类接口 - 它们是对象,但它们是作为全局变量处理的对象。这与对象上的实例方法的接口相反,其中任何其他对象可以在不依赖于对象的类的情况下被加入。

因此,在全局(如无范围的类定义)上使用类方法是,Dave认为,类似于使用全局方法,即PHP。

答案 1 :(得分:1)

我发现该文有几个问题:

首先,使用" symbol"可能会令人困惑。事实上,这个词确实完美地描述了作者的意思,但有些读者可能会将其与Ruby中的Symbol数据类型混淆。因此,虽然不是错误的,但在Ruby的上下文中,单词的选择是不幸的。 "名称"可能是一个更好的选择。

其次,他在类和实例方法之间进行了人为的区分,但在Ruby中没有类方法这样的东西。 Ruby只有一种方法:实例方法。我们称之为"单身方法"实际上只是单例类的常规实例方法,我们称之为"类方法"实际上只是一个对象的singleton类的常规实例方法,恰好是Class类的一个实例。

第三,他在类和对象之间进行了人为的区分,但类是Ruby中的对象

似乎我们真的争论反对,是常量(因为它们是全局名称),单例(通常是哪些类)和静态。虽然所有这些都是坏的当然是正确的,但他应该这样说,如果那是他的意思。 (它也不是一个新发现;整个编程语言都是基于避免静态设计的,例如Newspeak。)

tl; dr summary :这篇文章反对全球名称,单身人士和静态,但却被严重地呈现和表达。

答案 2 :(得分:1)

问题1

:some_instance_method:some_class_method符号仅存在于Ruby的符号表中。它们在符号的上下文中不同。 Symbol.all_symbols结果不会声明有关被引用对象的任何内容。如果你有:

class Aaa
  def kick_it
    logger.debug { "You kicked an Aaa object" }
  end
end
module Bbb
  def self.kick_it
    logger.debug { "You kicked Bbb" }
  end
end

:kick_it只会报告1 Symbol.all_symbols,即使其中一个是模块级方法而另一个是实例方法。

问题2

使用"符号"在文章中可能令人困惑。 A"全球符号"这可能意味着集合Object.constants的成员的名称,或者在定义的常量子树中可访问的任何其他常量。

因此Symbol.all_symbols与"全局符号"不同。在这种情况下。但是,内存常量树中的所有名称都是Symbol.all_symbols的子集,请记住,那里的所有范围信息都会丢失。

问题3

我认为上面的问题1 答案也解释了为什么两个符号都显示在Symbol.all_symbols结果中。