Skip to content

Ruby 变量

Ruby 变量 (Variables)、常量 (Constants) 和字面量 (Literals)

Section titled “Ruby 变量 (Variables)、常量 (Constants) 和字面量 (Literals)”

变量 (Variables) 是命名的内存位置,用于存储程序使用的数据。理解 Ruby 如何处理变量、常量 (Constants) 和各种数据字面量 (Literals),对于编写高效的 Ruby 代码至关重要。

Ruby 支持几种类型的变量,每种都有特定的作用域 (Scope) 和用途。本章将深入探讨这些类型,并在任何先前的简要介绍基础上进行更详细的阐述。

全局变量以美元符号 ($) 开头。例如,$admin_user。如果在初始化之前使用了全局变量,它的值为 nil(表示“无”或未定义)。如果 Ruby 运行带有 -w 或 -W(详细模式)标志,使用未初始化的全局变量会产生警告。

给全局变量赋值后,它可以在程序中的任何地方访问。然而,通常不鼓励广泛使用全局变量。它们可能使程序难以理解、调试 (Debug) 和维护,因为它们可以在任何地方被修改,导致意想不到的副作用 (Side Effects)。优先通过方法参数 (Method Arguments) 传递数据或使用其他作用域机制。

以下是演示全局变量用法的示例:

#!/usr/bin/env ruby
$global_variable = 10
class Class1
def print_global
puts "Global variable in Class1 is #{$global_variable}"
end
end
class Class2
def print_global
puts "Global variable in Class2 is #{$global_variable}"
end
end
class1_obj = Class1.new
class1_obj.print_global
class2_obj = Class2.new
class2_obj.print_global

在此示例中,$global_variable 在 Class1 和 Class2 中都可访问。此代码将输出:

Global variable in Class1 is 10
Global variable in Class2 is 10

字符串插值 (String Interpolation) 注意事项:在 Ruby 中,要在双引号字符串中嵌入变量或表达式的值,可以使用 #{expression} 语法。例如,"Value: #{my_variable}"。

实例变量以 @ 符号开头,例如,@user_name。它们属于类的特定实例 (Instance)(即对象 Object)。每个对象都有自己的一组实例变量。未初始化的实例变量值为 nil,如果在赋值前访问,使用 -w 选项会产生警告。

以下是实例变量的示例:

#!/usr/bin/env ruby
class Customer
def initialize(id, name, address)
@cust_id = id
@cust_name = name
@cust_address = address
end
def display_details
puts "Customer ID: #{@cust_id}"
puts "Customer Name: #{@cust_name}"
puts "Customer Address: #{@cust_address}"
end
end
# 创建对象
cust1 = Customer.new("1", "John Doe", "123 Main St, Anytown")
cust2 = Customer.new("2", "Jane Smith", "456 Oak Ave, Otherville")
# 调用方法
cust1.display_details
cust2.display_details

在这里,@cust_id、@cust_name 和 @cust_address 是实例变量。每个 Customer 对象都有这些变量自己的值。输出将是:

Customer ID: 1
Customer Name: John Doe
Customer Address: 123 Main St, Anytown
Customer ID: 2
Customer Name: Jane Smith
Customer Address: 456 Oak Ave, Otherville

类变量以两个 @ 符号开头,例如,@@total_users。它们在类的所有实例以及类本身及其子类 (Subclasses) 之间共享。类变量必须在使用它们的方法定义 (Method Definitions) 之前进行初始化,否则会发生错误。如果启用了 -w 选项,在子类中重写类变量可能导致警告。

以下是类变量的示例:

#!/usr/bin/env ruby
class Customer
@@no_of_customers = 0 # 初始化类变量
def initialize(id, name, address)
@cust_id = id
@cust_name = name
@cust_address = address
@@no_of_customers += 1
end
def display_details
puts "Customer ID: #{@cust_id}"
puts "Customer Name: #{@cust_name}"
puts "Customer Address: #{@cust_address}"
end
def self.total_no_of_customers # 类方法访问类变量
puts "Total number of customers: #{@@no_of_customers}"
end
end
# 创建对象
cust1 = Customer.new("1", "John Doe", "123 Main St, Anytown")
cust2 = Customer.new("2", "Jane Smith", "456 Oak Ave, Otherville")
# 调用类方法
Customer.total_no_of_customers
cust3 = Customer.new("3", "Robert Brown", "789 Pine Ln, Sometown")
Customer.total_no_of_customers

这里,@@no_of_customers 是一个类变量。它跟踪创建的 Customer 对象的总数。输出将是:

Total number of customers: 2
Total number of customers: 3

局部变量以小写字母或下划线 (_) 开头。例如,count 或 _temp。局部变量的作用域仅限于其声明所在的块 (Block)、方法 (Method)、类 (Class) 或模块 (Module) 定义。它们在其定义范围之外不可用。

如果引用未初始化的局部变量,Ruby 会将其解释为对同名方法的调用且不带参数。如果不存在这样的方法,则会引发 NameError。

按照局部变量命名约定给名称赋值,即可将其声明为局部变量。它存在直到其当前作用域结束。在上面的 Customer 类示例中,id、name 和 address(initialize 的参数)是该方法内的局部变量。

常量以大写字母开头。例如,Version 或 MAX_USERS。在类或模块内定义的常量可以在该类或模块内部访问。在任何类或模块外部定义的常量是全局可访问的。

常量不能在方法内定义。尝试引用未初始化的常量会导致 NameError。虽然 Ruby 允许您为已初始化的常量重新赋值,但这会产生警告,因为常量的设计用途是保存不会改变的值。

#!/usr/bin/env ruby
class Example
VAR1 = 100
VAR2 = 200
def show
puts "Value of first Constant is #{VAR1}"
puts "Value of second Constant is #{VAR2}"
end
end
# 创建对象
object = Example.new
object.show
# 从类外部访问常量(如果在顶级或使用作用域解析运算符定义)
# puts Example::VAR1 # 这是从外部需要时访问它的方式

这里,VAR1 和 VAR2 是常量。输出将是:

Value of first Constant is 100
Value of second Constant is 200

伪变量是特殊的关键字,行为类似于变量,但其值不能由您的代码赋值。它们具有预定义的含义。

  • self: 当前方法的接收对象。在类定义中但在实例方法外部,self 指代类本身。
  • true: 表示布尔真值。
  • false: 表示布尔假值。
  • nil: 表示 ‘无’ 或未定义的值。它是一个对象,是 NilClass 的唯一实例。
  • FILE: 当前源文件的路径。
  • LINE: 源文件中的当前行号。
  • ENCODING: 当前文件的脚本编码。

字面量是直接在源代码中表示的固定值。Ruby 的字面量规则通常很直观。

Ruby 支持整数。自 Ruby 2.4 起,Fixnum 和 Bignum 被统一到一个单独的 Integer 类中,该类自动处理任何大小的数字,仅受可用内存限制。您不再需要担心小整数和大整数之间的区别。

整数可以带有可选的前导符号。您可以使用进制指示符:0 用于八进制(例如,0o377 或 0377),0x 用于十六进制(例如,0xff),以及 0b 用于二进制(例如,0b1011)。下划线字符 (_) 可以用于数字内部以增强可读性,并且会被忽略(例如,1_234_567)。

字符前加问号 (?) 会得到其 ASCII/编码整数值(例如,?a 是字符 ‘a’ 的整数值,?\n 是换行符的整数值)。

示例:

123 # Decimal
1_234 # Decimal with underscore for readability
-500 # Negative decimal
0o377 # Octal (or 0377)
0xff # Hexadecimal
0b1011 # Binary
?a # Integer code for character 'a'
?\n # Integer code for newline (0x0a)
12345678901234567890 # A large integer

浮点数字面量 (Floating-Point Literals)

Section titled “浮点数字面量 (Floating-Point Literals)”

Ruby 支持浮点数(带小数点的数字)。它们是 Float 类的对象。

示例:

123.4 # Standard floating point
1.0e6 # Scientific notation (1.0 * 10^6)
4E20 # Scientific notation (dot not required if 'E' is present)
4e+20 # Sign for exponent is optional for positive

Ruby 字符串是字节序列,通常表示字符,并且是 String 类的对象。Ruby 支持多种创建字符串的方式:

  • 单引号字符串 (’…’): 执行最少的解释。反斜杠符号仅支持 ‘(表示字面单引号)和 \(表示字面反斜杠)。不执行插值 (#{…})。
  • 双引号字符串 (”…”): 支持广泛的反斜杠转义序列(见下文)并使用 #{expression} 进行表达式插值。
  • %q{…} 或 %Q{…}(及其他分隔符): 通用字符串引用。%q 的行为类似于单引号,%Q 的行为类似于双引号。您可以使用各种分隔符对,如 ()、[]、<>,甚至非成对字符,如 !…! 或 |…|。

单引号和双引号示例:

#!/usr/bin/env ruby
puts 'escape using \\ backslash'
puts 'That\'s right'
name = "Ruby"
puts "Hello, #{name}!\nThis is a new line."

运行结果:

escape using \ backslash
That's right
Hello, Ruby!
This is a new line.

字符串插值示例:

#!/usr/bin/env ruby
seconds_in_a_day = 24 * 60 * 60
puts "There are #{seconds_in_a_day} seconds in a day."

运行结果:

There are 86400 seconds in a day.

反斜杠转义符 (Backslash Notations)(双引号字符串中常用)

Section titled “反斜杠转义符 (Backslash Notations)(双引号字符串中常用)”

双引号字符串和类似上下文中支持的常见反斜杠转义序列:

符号 (Notation)表示的字符 (Character Represented)
\n换行符 (Newline) (0x0A)
\r回车符 (Carriage return) (0x0D)
\t水平制表符 (Horizontal tab) (0x09)
\f换页符 (Formfeed) (0x0C)
\b退格符 (Backspace) (0x08)
\a响铃/警报符 (Bell/Alert) (0x07)
\e转义符 (Escape) (0x1B)
\s空格 (Space) (0x20)
\字面反斜杠 (Literal backslash)
‘字面单引号 (Literal single quote)(在 %Q{} 中有用)
“字面双引号 (Literal double quote)(在 ”…” 中有用)
\nnn八进制表示法(n 为 0-7)
\xnn十六进制表示法(n 为 0-9, a-f, 或 A-F)
\u{nnnn …}Unicode 字符(例如,\u{41 42 43} 表示 “ABC”)
\unnnnUnicode 字符(恰好四个十六进制数字)

有关 Ruby 字符串的更多详细信息,包括编码和高级方法,请参阅官方 Ruby 文档中的 String 类。

数组字面量通过将一系列用逗号分隔的对象引用放在方括号 ([]) 之间创建。末尾的逗号将被忽略。

示例:

#!/usr/bin/env ruby
my_array = ["fred", 10, 3.14, "This is a string", "last element",]
my_array.each do |item|
puts item
end
# 词数组字面量(常用于字符串数组)
words = %w[this is a test]
puts words.inspect # => ["this", "is", "a", "test"]

运行结果 (针对 my_array 部分):

fred
10
3.14
This is a string
last element

有关数组的全面信息,请参阅 Array 类文档。

哈希字面量(也称为关联数组或字典)通过将一系列键值对放在花括号 ({}) 之间创建。键 (Key) 和值 (Value) 可以用 =>(哈希火箭,Hash Rocket)分隔,或者如果键是符号 (Symbol),可以用冒号 : 分隔(Ruby 1.9+ 语法)。末尾的逗号将被忽略。

示例:

#!/usr/bin/env ruby
# 旧语法(仍然有效)或当键不是符号时
colors_hash_rocket = { "red" => 0xf00, "green" => 0x0f0, "blue" => 0x00f }
# 现代语法(用于符号键,推荐)
colors_symbols = { red: 0xf00, green: 0x0f0, blue: 0x00f }
puts "Using hash rocket syntax:"
colors_hash_rocket.each do |key, value|
print "#{key} is #{value}\n"
end
puts "\nUsing symbol key syntax:"
colors_symbols.each do |key, value|
print "#{key} is #{value}\n"
end

运行结果:

Using hash rocket syntax:
red is 3840
green is 240
blue is 15
Using symbol key syntax:
red is 3840
green is 240
blue is 15

有关哈希的更多详细信息,请查阅 Hash 类文档。

范围 (Range) 表示一个具有起始值和结束值的区间。范围可以使用 s..e(包含结束值)和 s...e(不包含结束值)构建,或使用 Range.new。

当用作迭代器 (Iterator) 时,范围会按顺序产生区间内的每个值。

范围 (1..5) 包含值 1、2、3、4、5。范围 (1...5) 包含值 1、2、3、4。

示例:

#!/usr/bin/env ruby
puts "包含结束值的范围:"
(10..15).each do |n|
print n, ' '
end
puts
puts "\n不包含结束值的范围:"
(10...15).each do |n|
print n, ' '
end
puts

运行结果:

Inclusive range:
10 11 12 13 14 15
Exclusive range:
10 11 12 13 14

有关范围的更多信息,请参阅 Range 类文档。