内容 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11

官方 Ruby 常见问题解答

如果您想报告此常见问题解答中的错误或提出改进建议,请访问我们的 GitHub 存储库 并打开一个 issue 或 pull request。

语法

立即值和引用之间有什么区别?

本节或其中部分内容可能已过时或需要确认。

Fixnumtruenilfalse 被实现为立即值。对于立即值,变量保存的是对象本身,而不是对它们的引用。

不能为这些对象定义单例方法。两个具有相同值的 Fixnum 始终表示同一个对象实例,因此(例如)值为 1Fixnum 的实例变量在系统中所有的 1 之间共享。这使得不可能仅为一个 1 定义单例方法。

nilfalse 之间有什么区别?

首先是相似之处:nilfalse 是在布尔上下文中评估为 false 的仅有的两个对象。(换句话说:它们是仅有的“假值”,所有其他对象都是“真值”。)

但是,nilfalse 是不同类的实例(NilClassFalseClass),并且在其他地方有不同的行为。

我们建议谓词方法(名称以问号结尾的方法)返回 truefalse。其他需要指示失败的方法应返回 nil

为什么空字符串不是 false

问:空字符串 ("") 在条件表达式中返回 true!在 Perl 中,它是 false

答:但是 Ruby 不是 Perl ;-)。很简单:在 Ruby 中,只有 nilfalse 在条件上下文中为 false。

您可以使用 empty?,将字符串与 "" 进行比较,或将字符串的 sizelength0 进行比较,以确定字符串是否为空。

:name 是什么意思?

冒号后跟一个名称会生成一个 Symbol 对象,该对象与标识符一一对应。在程序执行期间,将为给定的名称或字符串创建相同的 Symbol 对象。也可以使用 "name".intern"name".to_sym 创建符号。

Symbol 对象可以表示方法、变量等的标识符。某些方法,如 define_methodmethod_missingtrace_var,需要一个符号。其他方法,例如 attr_accessorsendautoload,也接受字符串。

由于它们只被创建一次,因此 Symbol 通常用作哈希键。字符串哈希键会为每次使用创建一个新对象,从而导致一些内存开销。甚至还有用于符号哈希键的特殊语法

person_1 = { :name => "John", :age => 42 }
person_2 = { name: "Jane", age: 24 }        # alternate syntax

符号也可以用作枚举值或为常量分配唯一值

status = :open  # :closed, ...

NORTH = :NORTH
SOUTH = :SOUTH

如何访问符号的值?

要获取与符号对应的变量的值,您可以使用 symbol.to_s"#{symbol}" 来获取变量的名称,然后在符号的作用域中评估该名称以获取变量的内容

a = "This is the content of `a'"
b = eval("#{:a}")
a.object_id == b.object_id  # => true

您也可以使用

b = binding.local_variable_get(:a)

如果您的符号对应于方法的名称,则可以使用 send

class Demo
  def hello
    "Hello, world"
  end
end

demo = Demo.new
demo.send(:hello)

或者您可以使用 Object#method 返回一个相应的 Method 对象,然后您可以调用该对象

m = demo.method(:hello)  # => #<Method: Demo#hello>
m.call                   # => "Hello, world"

loop 是控制结构吗?

尽管 loop 看起来像一个控制结构,但它实际上是在 Kernel 中定义的方法。后面的块为局部变量引入了一个新的作用域。

Ruby 没有后测试循环

问:Ruby 没有 do { ... } while 构造,那么如何实现最后测试条件的循环?

Clemens Hintze 说:您可以使用 Ruby 的 begin ... endwhileuntil 语句修饰符的组合来实现相同的效果

i = 0
begin
  puts "i = #{i}"
  i += 1
end until i > 4

产生

i = 0
i = 1
i = 2
i = 3
i = 4

为什么我不能将哈希字面量传递给方法:p {}

{} 被解析为块,而不是 Hash 构造函数。您可以通过使它是一个参数的事实明确地强制将 {} 视为表达式:p({})

我无法让 def pos=(val) 工作!

我有以下代码,但我无法使用方法 pos = 1

def pos=(val)
  @pos = val
  puts @pos
end

附加了 = 的方法必须使用显式接收器调用(如果没有接收器,您只是在分配给局部变量)。将其作为 self.pos = 1 调用。

'\1''\\1' 之间有什么区别?

它们具有相同的含义。在单引号字符串中,只有 \'\\ 会被转换,其他组合保持不变。

但是,在双引号字符串中,"\1" 是字节 \001(一个八进制位模式),而 "\\1" 是包含反斜杠和字符 "1" 的两个字符的字符串。

..... 之间有什么区别?

.. 在范围中包含右侧,... 不包含

(5..8).to_a   # => [5, 6, 7, 8]
(5...8).to_a  # => [5, 6, 7]

or|| 之间有什么区别?

问:p(nil || "Hello") 打印 "Hello",而 p(nil or "Hello") 给出解析错误。为什么?

答:or 的优先级非常低,p( (nil or "Hello") ) 将会起作用。

例如,or 的优先级也低于 = 的优先级,而 || 的优先级更高

foo = nil || "Hello"  # parsed as: foo = (nil || "Hello")
foo  # => "Hello"

# but perhaps surprisingly:

foo = nil or "Hello"  # parsed as: (foo = nil) or "Hello"
foo  # => nil

or(以及类似的 and)最好不要用于组合布尔表达式,而是用于控制流,如

do_something  or raise "some error!"

当发生错误时,do_something 返回 falsenil

Ruby 有函数指针吗?

Proc.newproclambda 生成的 Proc 对象可以从变量中引用,因此可以说该变量是函数指针。您还可以使用 object.method 获取对特定对象实例中方法的引用。

loadrequire 之间有什么区别?

load 将加载并执行 Ruby 程序 (*.rb)。

require 也加载 Ruby 程序,但也会加载二进制 Ruby 扩展模块(共享库或 DLL)。此外,require 确保一个功能永远不会被多次加载。

Ruby 有异常处理吗?

Ruby 支持灵活的异常处理方案

begin
  statements which may raise exceptions
rescue [exception class names]
  statements when an exception occurred
rescue [exception class names]
  statements when an exception occurred
ensure
  statements that will always run
end

如果在 begin 子句中发生异常,则会执行具有匹配异常名称的 rescue 子句。无论是否发生异常,都会执行 ensure 子句。rescueensure 子句可以省略。

如果没有为 rescue 子句指定异常类,则默认使用 StandardError 异常,并且会捕获与 StandardError 存在 is_a? 关系的异常。

此表达式返回 begin 子句的值。

可以通过全局变量 $! 访问最近发生的异常(因此可以使用 $!.type 确定其类型)。