如果您想报告此常见问题解答中的错误或提出改进建议,请访问我们的 GitHub 存储库 并打开一个 issue 或 pull request。
语法
立即值和引用之间有什么区别?
本节或其中部分内容可能已过时或需要确认。
Fixnum
、true
、nil
和 false
被实现为立即值。对于立即值,变量保存的是对象本身,而不是对它们的引用。
不能为这些对象定义单例方法。两个具有相同值的 Fixnum
始终表示同一个对象实例,因此(例如)值为 1
的 Fixnum
的实例变量在系统中所有的 1
之间共享。这使得不可能仅为一个 1
定义单例方法。
nil
和 false
之间有什么区别?
首先是相似之处:nil
和 false
是在布尔上下文中评估为 false
的仅有的两个对象。(换句话说:它们是仅有的“假值”,所有其他对象都是“真值”。)
但是,nil
和 false
是不同类的实例(NilClass
和 FalseClass
),并且在其他地方有不同的行为。
我们建议谓词方法(名称以问号结尾的方法)返回 true
或 false
。其他需要指示失败的方法应返回 nil
。
为什么空字符串不是 false
?
问:空字符串 (""
) 在条件表达式中返回 true
!在 Perl 中,它是 false
。
答:但是 Ruby 不是 Perl ;-)。很简单:在 Ruby 中,只有 nil
和 false
在条件上下文中为 false。
您可以使用 empty?
,将字符串与 ""
进行比较,或将字符串的 size
或 length
与 0
进行比较,以确定字符串是否为空。
:name
是什么意思?
冒号后跟一个名称会生成一个 Symbol 对象,该对象与标识符一一对应。在程序执行期间,将为给定的名称或字符串创建相同的 Symbol 对象。也可以使用 "name".intern
或 "name".to_sym
创建符号。
Symbol 对象可以表示方法、变量等的标识符。某些方法,如 define_method
、method_missing
或 trace_var
,需要一个符号。其他方法,例如 attr_accessor
、send
或 autoload
,也接受字符串。
由于它们只被创建一次,因此 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 ... 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
确定其类型)。