为什么Ruby文档中的方法前面有一个井号(#)?

66

当我看到任何 Ruby 方法在文本中打印时,通常会显示为:

Class#method

或者

#method

现在,我会使用:

Class.method

为什么所有的 Ruby 方法都以井号开头?这有什么原因吗?


它追溯到什么时候? - nafg
3
这个术语首次出现在《Ruby编程》第一版中,该书于2001年出版:https://ruby-doc.com/docs/ProgrammingRuby/html/preface.html#S10 - 这种符号表示法的选择在2005年发行的第二版中得到了更清晰的解释。 - ioquatix
8个回答

111

请注意,惯例是:

Class#method

而不是

object#method

在代码中,如果objectclass的实例,你会写成object.method。在代码中不使用#约定。

根据RDoc文档

使用::描述类方法,#描述实例方法,.用于示例代码。


是的,抱歉,Class#Method。谢谢。 - Ed S.
1
我知道在代码中不使用#,但为什么它会被使用呢? - Ed S.

31

#符号用于引用规范的instance方法,例如String#upcase。点符号用于引用特定实例的方法,例如mystring.upcase。这样做是为了不暗示类方法'upcase'的存在。


20

我刚意识到其他回答中没有碰到这个问题最微不足道的方面: 为什么使用 # 符号?

我有两个理论:

  1. 它可能来自 Smalltalk,在那里符号被写成 #sym(而不是像 Ruby 中的 :sym)。因此,如果您想要 引用 方法 对象(而不是调用方法),那么您将调用类似于 Array >> #new 的东西。(>> 本身就是一种返回传递给它的方法的方法。因此,在 Ruby 中,这将是 Array.method :new。)在 Smalltalk 文档中,方法通常被称为 Class>>method,但在 Ruby 中,Class:method 更合理,除了它很容易与 Class::method 混淆。因此,选择了 Class#method
  2. 我的另一个理论是,简单地选择了 #,因为在 Ruby 中它是注释字符。

只有发明这个约定的人才能给出明确的答案。如果它是为《Programming Ruby》书而发明的,那么可能是 Dave Thomas 或 Andy Hunt,但我有点怀疑。该书出版于 2001 年,Ruby 开始于 1993 年,他们在那之前是如何引用方法的呢?


2
我听说实用主义程序员也创建了Ruby的文档(他们想要种下文档的种子,以便其他人会被“愚弄”而添加到其中)。Git可以带你回到1998年,所以你可以检查Class#method_name是否在实用主义程序员添加之前就存在。 - Andrew Grimm
我后来听说,在Prag Progs开始将文档添加到源代码之前,文档确实存在。 - Andrew Grimm
3
也许它是在模仿 HTML 中锚点语法的外观。例如,http://www.somesite.com/somepage#section。 - BHS
4
我同意这个观点。在缺乏任何明确资源解释为什么选择 # 的情况下,我一直认为最可能的解释是用于跳转到文档中特定方法的锚点——Java 也被广泛认为起源于此。 - javawizard

18

来自rdoc文档(注意加粗部分):

在注释文本中,类的名称、源文件以及任何方法名称,如果包含下划线或以井号字符开头,则会自动从注释文本中创建超链接到它们的描述。


8
哈希符号是在2000年12月首次出版的《编程 Ruby - 实用程序员指南》中引入的。
“前言”中包含{{link1:“符号约定”}}:

在文本中,Fred#doIt 是对 class Fred 的实例方法(doIt)的引用,而 Fred.new [在其他一些 Ruby 文档中,您可能会看到类方法写成 Fred::new。这是完全有效的 Ruby 语法;我们只是觉得 Fred.new 更不容易分心。] 是一个类方法,而 Fred::EOF 是一个类常量。

这在2004年10月出版的第二版中得到了澄清。
在这段文字中,Fred#do_something 是对class Fred的实例方法(在此情况下是do_something)的引用,Fred.new是一个类方法,Fred::EOF是一个类常量。使用井号来表示实例方法是一个艰难的决定:它不是有效的Ruby语法,但我们认为区分特定类的实例方法和类方法很重要。当你看到我们写File.read时,你知道我们正在谈论类方法read。而当我们写File#read时,我们指的是实例方法read。Ruby本身也使用这种表示法。
> rvm use 1.9.3
Using ruby-1.9.3-p551

> Object.instance_method(:initialize)
=> #<UnboundMethod: Object(BasicObject)#initialize>

它是由Matz于2002年2月引入和正式化的:Matz in February 2002
commit 8210c254bee19294af67bcee0e8f5e02ebb39a60
Author: matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date:   Tue Feb 5 07:56:31 2002 +0000

    * io.c (fptr_finalize): should raise error when fclose fails.

    * eval.c (method_inspect): proper output format to distinguish
      methods and singleton methods.


    git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2046 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

7

以上所有答案都是正确的。我要补充的一点是,你所说的文档风格

Class.method

很容易与类方法混淆。因为在Ruby中,你可以使用上述语法调用类方法:

class Foo
  def self.say_hi
    puts "hi"
  end
end

Foo.say_hi    # => prints "hi"

4
这在此问题的JavaScript版本中提到过,但很可能这个术语是来自JavaDoc,其中井号直接被翻译为页面引用,例如href="Component.html#getComponentAt(int, int)"

1
哦,我一直在想为什么Javadoc需要那种用法,但我没想到原因会如此平凡。 - JAB

1
我认为,heff的答案(由于声望不足,我无法评论)是最好的猜测,即Ruby遵循了JavaDoc的例子。JavaDoc设计者需要或想要一种区分包限定符(他们使用点)和类限定符(他们使用井号)的方法。JavaDoc的@see和@link标签语法如下:
@see   package.class#member [optional label]
{@link package.class#member [optional label]}

请查看 JavaDoc's package.class 变种的 @see 标签 的文档以及 JavaDoc 的 @link 标签的文档,heff 已经指向了它们。
在 JavaDoc 中,包名通常可以省略,因此只剩下 Class#member 部分,这与 Ruby 中一样奇怪,因为 Java 代码使用 Class.member 语法,就像 Ruby 一样。
有趣的是,我们想知道 JavaDoc 设计者为什么需要不同的语法,而 Java 编译器对于两种情况都可以使用点号。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接