Ruby中方法名称的限制是什么?

时间:2012-05-10 21:23:49

标签: ruby

例如,我在以下代码段中找到了方法名称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

5 个答案:

答案 0 :(得分:75)

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

方法名称不能以数字开头,而!?=字符只能出现在最后。

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

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

def Capital
    nil
end

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

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

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

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

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

    < / LI>
  4. Setters 与最后一个字符具有等号=(例如Array#[]=,...); Ruby interpeter为setter方法的调用提供语法糖

    a = [4, 5, 6]
    a[0] = 3    # Shorthand for a.[]=(0, 3)
    
  5. 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 ║
    ╚═══════════════════════════╩═════════════════════════════════════════════╩═══════╝
    

    一元运算符方法没有参数传递;二元运算符方法传递一个参数,并对它进行操作self

    严格遵守经营者的意见非常重要;虽然可以使用不同的arity定义operator方法(例如,带有两个参数的+方法),Ruby不允许您使用运算符语法调用该方法(但是它将使用点语法)。< / p>

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

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

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

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

答案 1 :(得分:6)

其他人对内置语法的说法是正确的,但是如果使用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

Testing Guide上提到了这一点。

好奇心:类似的事情发生在Java中,字节码方法名称提供了比Java语言更多的选择:Why does the JVM allow us to name a function starting with a digit in bytecode?

答案 2 :(得分:2)

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

答案 3 :(得分: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&#39; JBuilder的:

https://github.com/rails/jbuilder

O&#39; Reilly Ruby书籍的第196页记录了这些内容:

  

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

z = f.(x,y)
     

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

答案 4 :(得分:0)

允许的字符为:a-Z,0-9,只要不在开头,_?(对于布尔函数)和! (用于破坏性功能)和=(用于设置者)。