Ruby符号 #
一、符号概述 #
符号(Symbol)是Ruby特有的数据类型,它是一个不可变的标识符。符号以冒号开头,在整个程序中唯一。
ruby
:name
:age
:user_name
:"hello world"
二、符号的特点 #
2.1 不可变性 #
符号一旦创建就不能修改:
ruby
s = :name
s[0] = 'N'
str = "name"
str[0] = 'N'
2.2 唯一性 #
相同名称的符号是同一个对象:
ruby
:name.object_id
:name.object_id
:name.object_id == :name.object_id
"name".object_id
"name".object_id
"name".object_id == "name".object_id
2.3 内存效率 #
ruby
symbols = []
strings = []
10000.times { symbols << :name }
10000.times { strings << "name" }
symbols.uniq.size
strings.uniq.size
symbols.map(&:object_id).uniq.size
strings.map(&:object_id).uniq.size
三、创建符号 #
3.1 字面量语法 #
ruby
:name
:user_name
:UserClass
:method_name?
:dangerous_method!
3.2 引号语法 #
ruby
:"hello world"
:"user-name"
:"class name"
:'single quotes'
3.3 动态创建 #
ruby
"name".to_sym
"user_name".intern
:"prefix_#{name}"
3.4 符号数组 #
ruby
%i[apple banana cherry]
%I[apple banana #{fruit}]
%i(apple banana cherry)
%w[apple banana cherry]
四、符号与字符串转换 #
4.1 符号转字符串 #
ruby
:name.to_s
:name.id2name
:name.inspect
4.2 字符串转符号 #
ruby
"name".to_sym
"name".intern
4.3 安全转换 #
ruby
def to_safe_symbol(str)
str.to_s.gsub(/[^a-zA-Z0-9_]/, '_').to_sym
end
to_safe_symbol("hello world")
to_safe_symbol("user-name")
五、符号方法 #
5.1 基本方法 #
ruby
:name.length
:name.empty?
:name.size
:name.to_s
:name.to_sym
:name.id2name
:name.inspect
:name.downcase
:name.upcase
:name.capitalize
5.2 比较方法 #
ruby
:name == :name
:name.eql?(:name)
:name.equal?(:name)
:name <=> :name
:name.casecmp(:NAME)
:name.casecmp?(:NAME)
5.3 匹配方法 #
ruby
:name =~ /name/
:name.match(/name/)
:name.match?(/name/)
:name.start_with?(:n)
:name.end_with?(:e)
5.4 转换方法 #
ruby
:name.to_proc
:name.to_s
:name.to_sym
:name.dup
:name.clone
六、符号的使用场景 #
6.1 哈希键 #
ruby
user = {
name: "Ruby",
age: 30,
email: "ruby@example.com"
}
puts user[:name]
puts user[:age]
user[:name] = "Rails"
user[:city] = "Beijing"
6.2 方法名引用 #
ruby
class Person
attr_accessor :name, :age
def initialize(name, age)
@name = name
@age = age
end
end
person = Person.new("Ruby", 30)
person.send(:name)
person.public_send(:age)
person.respond_to?(:name)
person.methods.include?(:name)
6.3 关键字参数 #
ruby
def greet(name:, age:, city: "Beijing")
puts "Hello, #{name} from #{city}, age #{age}"
end
greet(name: "Ruby", age: 30)
greet(age: 25, name: "Rails", city: "Shanghai")
6.4 attr系列方法 #
ruby
class User
attr_reader :id
attr_writer :password
attr_accessor :name, :email
def initialize(id)
@id = id
end
end
6.5 定义方法 #
ruby
class Person
define_method :greet do |name|
puts "Hello, #{name}!"
end
end
person = Person.new
person.greet("Ruby")
6.6 回调与钩子 #
ruby
class Model
def before_save
puts "Before save"
end
def after_save
puts "After save"
end
def save
before_save
puts "Saving..."
after_save
end
end
七、符号与字符串的选择 #
7.1 使用符号的场景 #
- 哈希键
- 方法名引用
- 关键字参数
- 枚举值
- 固定的标识符
ruby
STATUS = {
pending: :pending,
approved: :approved,
rejected: :rejected
}
config = {
adapter: :postgresql,
encoding: :unicode,
pool: 5
}
7.2 使用字符串的场景 #
- 用户输入
- 动态内容
- 需要修改的内容
- 文本处理
ruby
user_input = gets.chomp
dynamic_content = "Hello, #{name}"
mutable_text = "Hello"
mutable_text << " World"
7.3 性能对比 #
ruby
require 'benchmark'
n = 1_000_000
Benchmark.bm do |x|
x.report("Symbol: ") do
n.times { :name }
end
x.report("String: ") do
n.times { "name" }
end
x.report("Symbol hash: ") do
n.times { { name: "value" } }
end
x.report("String hash: ") do
n.times { { "name" => "value" } }
end
end
八、符号表 #
8.1 查看所有符号 #
ruby
Symbol.all_symbols
Symbol.all_symbols.size
Symbol.all_symbols.grep(/user/)
8.2 符号垃圾回收 #
Ruby 2.2+ 支持符号垃圾回收:
ruby
GC.start
Symbol.all_symbols.size
8.3 避免符号泄露 #
ruby
def dangerous_method(user_input)
user_input.to_sym
end
def safe_method(user_input)
user_input.to_s
end
九、符号与to_proc #
9.1 基本用法 #
ruby
[1, 2, 3].map(&:to_s)
[1, 2, 3].map { |n| n.to_s }
["a", "b", "c"].map(&:upcase)
["a", "b", "c"].map { |s| s.upcase }
9.2 原理解析 #
ruby
class Symbol
def to_proc
Proc.new { |obj, *args| obj.send(self, *args) }
end
end
[1, 2, 3].map(&:to_s)
[1, 2, 3].map { |n| n.send(:to_s) }
9.3 高级用法 #
ruby
users = [{ name: "Alice" }, { name: "Bob" }]
users.map { |u| u[:name] }
users.map(&:[]).map(&:name)
[1, 2, 3, 4, 5].select(&:even?)
[1, 2, 3, 4, 5].reject(&:odd?)
[1, 2, 3, 4, 5].sum(&:abs)
十、实用示例 #
10.1 状态机 #
ruby
class Order
STATES = %i[pending processing shipped delivered cancelled].freeze
attr_reader :state
def initialize
@state = :pending
end
def process!
transition_to(:processing)
end
def ship!
transition_to(:shipped)
end
def deliver!
transition_to(:delivered)
end
def cancel!
transition_to(:cancelled)
end
private
def transition_to(new_state)
@state = new_state if STATES.include?(new_state)
end
end
10.2 配置选项 #
ruby
class Config
OPTIONS = %i[debug verbose log_level].freeze
def initialize
@options = {}
end
def configure(options)
options.each do |key, value|
@options[key] = value if OPTIONS.include?(key)
end
end
def method_missing(name, *args)
if OPTIONS.include?(name) && args.empty?
@options[name]
else
super
end
end
end
10.3 属性访问器 #
ruby
class Attributes
def initialize
@attributes = {}
end
def [](key)
@attributes[key.to_sym]
end
def []=(key, value)
@attributes[key.to_sym] = value
end
def method_missing(name, *args)
if name.end_with?('=')
self[name[0..-2].to_sym] = args.first
else
self[name]
end
end
end
attrs = Attributes.new
attrs.name = "Ruby"
attrs.age = 30
puts attrs.name
十一、最佳实践 #
11.1 哈希键使用符号 #
ruby
# 推荐
user = { name: "Ruby", age: 30 }
# 不推荐
user = { "name" => "Ruby", "age" => 30 }
11.2 关键字参数使用符号 #
ruby
def create_user(name:, email:, role: :member)
puts "Creating #{role} user: #{name} <#{email}>"
end
create_user(name: "Ruby", email: "ruby@example.com")
create_user(name: "Admin", email: "admin@example.com", role: :admin)
11.3 避免动态创建符号 #
ruby
# 危险:可能导致符号泄露
def process(user_input)
user_input.to_sym
end
# 安全:使用字符串
def process(user_input)
user_input.to_s
end
十二、总结 #
本章我们学习了:
- 符号特点:不可变、唯一、内存高效
- 创建方式:字面量、引号语法、动态创建
- 使用场景:哈希键、方法引用、关键字参数
- 符号与字符串:选择合适的类型
- to_proc:简化迭代器调用
- 最佳实践:避免符号泄露
接下来让我们学习Ruby的空值nil!
最后更新:2026-03-27