官方 Ruby FAQ
如果您希望报告错误或对本 FAQ 提出改进建议,请访问我们的 GitHub 仓库,并提出 issue 或 pull request。
语法
立即值和引用有什么区别?
本节或部分内容可能已过时或需要确认。
Fixnum、true、nil 和 false 都被实现为立即值。对于立即值,变量保存的是对象本身,而不是对象的引用。
无法为这些对象定义单例方法。具有相同值的两个 Fixnum 始终代表同一个对象实例,因此(例如)值为 1 的 Fixnum 的实例变量在系统中的所有 1 之间共享。这使得无法仅为其中一个定义单例方法。
nil 和 false 有什么区别?
首先是相似之处:在布尔上下文中,nil 和 false 是唯一求值为 false 的两个对象。(换句话说:它们是唯一的“假值”,所有其他对象都是“真值”。)
但是,nil 和 false 是不同类的实例(NilClass 和 FalseClass),并且在其他地方具有不同的行为。
我们建议谓词方法(名称以问号结尾的方法)返回 true 或 false。其他需要指示失败的方法应返回 nil。
为什么空字符串不是 false?
问:空字符串("")在条件表达式中返回 true!在 Perl 中,它是 false。
答:但 Ruby 不是 Perl ;-)。很简单:在 Ruby 中,只有 nil 和 false 在条件上下文中是假的。
您可以使用 empty?,将字符串与 "" 进行比较,或将字符串的 size 或 length 与 0 进行比较,来判断一个字符串是否为空。
:name 是什么意思?
冒号后跟一个名称会生成一个 Symbol 对象,该对象与标识符一一对应。在程序执行期间,对于给定的名称或字符串,将创建相同的 Symbol 对象。也可以使用 "name".intern 或 "name".to_sym 创建 Symbol。
Symbol 对象可以表示方法、变量等的标识符。一些方法,如 define_method、method_missing 或 trace_var,需要 Symbol。其他方法,例如 attr_accessor、send 或 autoload,也接受字符串。
由于它们只创建一次,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 ... end 和 while 或 until 语句修饰符的组合来实现相同效果
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 在发生错误时返回 false 或 nil。
Ruby 有函数指针吗?
由 Proc.new、proc 或 lambda 生成的 Proc 对象可以被一个变量引用,所以可以说该变量是一个函数指针。您也可以使用 object.method 来获取特定对象实例中方法的引用。
load 和 require 有什么区别?
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 子句。rescue 和 ensure 子句可以省略。
如果未为 rescue 子句指定异常类,则隐含 StandardError 异常,并且会捕获与 StandardError 处于 is_a? 关系下的异常。
此表达式返回 begin 子句的值。
最后一个异常可以通过全局变量 $! 访问(因此可以使用 $!.type 确定其类型)。