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

官方 Ruby FAQ

如果您希望报告错误或对本 FAQ 提出改进建议,请访问我们的 GitHub 仓库,并提出 issue 或 pull request。

语法

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

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

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

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

nilfalse 有什么区别?

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

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

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

为什么空字符串不是 false

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

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

您可以使用 empty?,将字符串与 "" 进行比较,或将字符串的 sizelength0 进行比较,来判断一个字符串是否为空。

:name 是什么意思?

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

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

由于它们只创建一次,Symbol 经常用作哈希键。字符串哈希键每次使用都会创建一个新对象,从而产生一些内存开销。甚至还有一个用于 Symbol 哈希键的特殊语法

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

Symbol 也可用作枚举值或为常量赋值唯一值

status = :open  # :closed, ...

NORTH = :NORTH
SOUTH = :SOUTH

如何访问 Symbol 的值?

要获取与 Symbol 对应的变量的值,您可以使用 symbol.to_s"#{symbol}" 来获取变量的名称,然后在 Symbol 的作用域中对其进行求值以获取变量的内容

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

您也可以使用

b = binding.local_variable_get(:a)

如果您的 Symbol 对应于方法名称,您可以使用 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 确定其类型)。