49

例如,我bundler?在下面的代码片段中找到了方法名称,不知道该?字符是专门的关键字还是只是方法名称的一部分。

# This is a predicate useful for the doc:guides task of applications.
def bundler?
  # Note that rake sets the cwd to the one that contains the Rakefile
  # being executed.
  File.exists?('Gemfile')
end
4

5 回答 5

85

Ruby 中的方法名称可以包含大小写字母、数字、下划线_和标点符号!, ?, =

方法名不能以数字和字符开头,只能!出现在末尾。?=

方法名称中可以使用非 ASCII 字符,但这可能会导致非常混乱的情况,不应该成为常见的做法。

以小写字符开头的方法名称虽然不是强制性的,但这是一种很好的做法,因为以大写字母开头的名称在 Ruby 中是常量。仍然可以为方法使用常量名称,但是如果没有括号,您将无法调用它,因为解释器将查找名称作为常量:

def Capital
    nil
end

Capital    # NameError: uninitialized constant Capital
Capital()  # => nil

在定义方法名称时,一些非常广泛且一致使用的约定是:

  1. 方法名称是全小写的,下划线_作为名称中单词的分隔符(例如Math::sqrt,,Array#each_index...)。

  2. 谓词有一个问号?作为最后一个字符(例如Array#empty?, Hash#has_key?, ...)。虽然谓词通常返回布尔值,但情况并非总是如此:这些方法只需要返回nil,或者false如果谓词评估为假,则返回任何其他值(例如,如果文件不存在则File::size?返回,文件大小作为否则返回)。nilInteger

  3. 修改调用它们的对象的状态或具有异常行为的方法!在最后一个字符中带有感叹号;这种方法有时被称为mutators,因为它们通常是其他方法的破坏性或就地版本(例如Array#sort!, Array#slice!, ...)。

  4. 设置器的最后一个字符是等号=(例如Array#[]=,...);Ruby interpeter为调用 setter 方法提供了语法糖:

    a = [4, 5, 6]
    a[0] = 3    # Shorthand for a.[]=(0, 3)
    

Ruby 还允许使用运算符符号作为方法名称来定义运算符:

╔═══════════════════════════╦═════════════════════════════════════════════╦═══════╗
║ Operators (by precedence) ║                 Operations                  ║ Arity ║
╠═══════════════════════════╬═════════════════════════════════════════════╬═══════╣
║ ! ~ +                     ║ Boolean NOT, bitwise complement, unary plus ║     1 ║
║                           ║ (define with method name +@, Ruby 1.9+)     ║       ║
║                           ║                                             ║       ║
║ **                        ║ Exponentiation                              ║     2 ║
║                           ║                                             ║       ║
║ -                         ║ Unary minus (define with method name -@)    ║     1 ║
║                           ║                                             ║       ║
║ * / %                     ║ Multiplication, division, modulo            ║     2 ║
║                           ║                                             ║       ║
║ + -                       ║ Addition, subtraction                       ║     2 ║
║                           ║                                             ║       ║
║ << >>                     ║ Bitwise shift                               ║     2 ║
║                           ║                                             ║       ║
║ &                         ║ Bitwise AND                                 ║     2 ║
║                           ║                                             ║       ║
║ | ^                       ║ Bitwise OR, Bitwise XOR                     ║     2 ║
║                           ║                                             ║       ║
║ < <= => >                 ║ Ordering                                    ║     2 ║
║                           ║                                             ║       ║
║ == === != =~ !~ <=>       ║ Equality, pattern matching, comparison      ║     2 ║
╚═══════════════════════════╩═════════════════════════════════════════════╩═══════╝

一元运算符方法不传递参数;二元运算符方法被传递一个参数,并对它和 on 进行操作self

重要的是要严格遵守运营商的严谨性;虽然可以定义具有不同数量的运算符方法(例如,一个带有+两个参数的方法),但 Ruby 不允许您使用运算符语法调用该方法(但它可以使用点语法)。

最好的做法是尽可能地遵守运算符的原始语义:对于知道运算符的原始含义的人来说,它应该是直观的,它如何与用户定义的类一起工作。

该语言还为通常用于访问数组和哈希值的特殊非运算符方法提供语法糖。[][]方法可以任意定义。

对于表中的每个二元运算符,除了排序、相等、比较和模式匹配,Ruby 还提供缩写赋值的简写(例如x += y扩展为x = x + y);您不能将它们定义为方法,但您可以更改它们的行为,定义它们所基于的运算符。

这些字符都不能在普通方法名称中使用(例如do&print,或者start-up不是有效的方法名称)。

于 2012-05-10T21:44:33.813 回答
7

其他人所说的内置语法是正确的,但是如果您使用define_method+之类的方法,似乎对可以使用的内容没有后端限制send

define_method(:'$% ^&') { 0 }
define_method(:'你好') { 1 }

send(:'$% ^&') == 0 or raise
send(:'你好') == 1 or raise

这个事实可能很有用:例如 Rails 的ActiveSupport::Testing::Declarative.test方法使用它以避免对以下内容进行复杂的转换:

test 'Some Controller#Method' do

到一个更健全的名称,这可能与另一个名为的测试冲突:

test 'Some Controller_Method' do

测试指南中提到了这一点。

好奇心:类似的事情发生在 Java 中,字节码方法名称比 Java 语言提供了更多选择:为什么 JVM 允许我们以字节码中的数字开头命名函数?

于 2014-11-09T20:42:27.363 回答
3

方法名称可以以!,?=. 也允许使用下划线。除此之外,您还可以为自己的类定义一些看起来像运算符的方法(例如+, *, >>, )。[]

于 2012-05-10T21:43:30.867 回答
2

添加一件事:您还可以告诉对象运行一个根本没有名称的方法,它会尝试调用一个名为的方法call

#!/usr/bin/env ruby

class Foo

=begin
  def call(*args)
    puts "received call with #{args.join(' ')}"
  end
=end

  def method_missing(m, *args, &block)
    puts "received method_missing on `#{m}(#{args.join(', ')})`"
  end

end

f = Foo.new
f.('hi')             # Not a syntax error! method_missing with m of :call
f.send :'', 'hmm'    # method_missing with m set to :''
f.send nil, 'bye'    # raises an error

实际上并没有call在 上定义任何名为的方法Object,但在MethodProc类上有一个。

在某些语言()中是用于函数调用的运算符,这似乎与这里发生的情况非常相似。

这在 Rails 的 JBuilder 中使用:

https://github.com/rails/jbuilder

它记录在 O'Reilly Ruby 书的第 196 页:

Ruby 1.9 提供了另一种调用Proc对象的方法。作为方括号的替代方法,您可以使用以句点为前缀的括号:

z = f.(x,y)

.()看起来像缺少方法名称的方法调用。这不是一个可以定义的运算符,而是调用该call方法的语法糖。它可以与定义call方法的任何对象一起使用,并且不限于Proc对象。

于 2015-02-12T16:46:36.020 回答
0

允许的字符是:a-Z,0-9只要不在开头,_?(对于布尔函数)和!(对于破坏性函数)和=(对于 setter)。

于 2012-05-10T21:43:26.050 回答