name: ruby-standard-library user-invocable: false description: 当使用Ruby标准库时使用,包括Enumerable、文件I/O、时间/日期、正则表达式和核心类。 allowed-tools:
- Bash
- Read
- Write
- Edit
Ruby标准库
掌握Ruby丰富的标准库。Ruby附带强大的内置类和方法,优雅地处理常见编程任务。
Enumerable
Enumerable模块为集合提供迭代方法。
常见的Enumerable方法
numbers = [1, 2, 3, 4, 5]
# map/collect - 转换元素
numbers.map { |n| n * 2 } # [2, 4, 6, 8, 10]
numbers.map(&:to_s) # ["1", "2", "3", "4", "5"]
# select/filter - 保留匹配条件的元素
numbers.select { |n| n.even? } # [2, 4]
numbers.filter(&:odd?) # [1, 3, 5]
# reject - 移除匹配条件的元素
numbers.reject { |n| n.even? } # [1, 3, 5]
# find/detect - 第一个匹配条件的元素
numbers.find { |n| n > 3 } # 4
# find_all - 所有匹配条件的元素(select的别名)
numbers.find_all { |n| n > 2 } # [3, 4, 5]
# reduce/inject - 累积值
numbers.reduce(0) { |sum, n| sum + n } # 15
numbers.reduce(:+) # 15
numbers.reduce(:*) # 120
# each - 遍历元素
numbers.each { |n| puts n }
# each_with_index - 带索引遍历
numbers.each_with_index { |n, i| puts "#{i}: #{n}" }
# each_with_object - 带可变对象遍历
numbers.each_with_object({}) { |n, hash| hash[n] = n * 2 }
# any? - 如果有任何元素匹配则为真
numbers.any? { |n| n > 4 } # true
numbers.any?(&:even?) # true
# all? - 如果所有元素匹配则为真
numbers.all? { |n| n > 0 } # true
numbers.all?(&:even?) # false
# none? - 如果没有元素匹配则为真
numbers.none? { |n| n < 0 } # true
# one? - 如果恰好一个元素匹配则为真
numbers.one? { |n| n == 3 } # true
# partition - 分割为两个数组[匹配, 不匹配]
evens, odds = numbers.partition(&:even?)
# group_by - 按键分组元素
numbers.group_by { |n| n % 2 == 0 ? :even : :odd }
# => {:odd=>[1, 3, 5], :even=>[2, 4]}
# chunk - 分组连续元素
[1, 2, 2, 3, 3, 3, 4].chunk(&:itself).to_a
# => [[1, [1]], [2, [2, 2]], [3, [3, 3, 3]], [4, [4]]]
# take - 前n个元素
numbers.take(3) # [1, 2, 3]
# drop - 跳过前n个元素
numbers.drop(3) # [4, 5]
# take_while - 元素直到条件失败
numbers.take_while { |n| n < 4 } # [1, 2, 3]
# drop_while - 跳过元素直到条件失败
numbers.drop_while { |n| n < 4 } # [4, 5]
# zip - 组合数组
[1, 2, 3].zip(['a', 'b', 'c']) # [[1, "a"], [2, "b"], [3, "c"]]
# min, max
numbers.min # 1
numbers.max # 5
numbers.minmax # [1, 5]
# sort
[3, 1, 4, 1, 5].sort # [1, 1, 3, 4, 5]
['猫', '狗', '鸟'].sort_by(&:length)
# uniq - 移除重复元素
[1, 2, 2, 3, 3, 3].uniq # [1, 2, 3]
# compact - 移除nil值
[1, nil, 2, nil, 3].compact # [1, 2, 3]
# flat_map - 映射并展平
[[1, 2], [3, 4]].flat_map { |arr| arr.map { |n| n * 2 } } # [2, 4, 6, 8]
# tally - 计数出现次数
['a', 'b', 'a', 'c', 'b', 'a'].tally # {"a"=>3, "b"=>2, "c"=>1}
数组
# 创建
arr = [1, 2, 3]
arr = Array.new(3, 0) # [0, 0, 0]
arr = Array.new(3) { |i| i * 2 } # [0, 2, 4]
# 访问
arr[0] # 第一个元素
arr[-1] # 最后一个元素
arr[1..3] # 范围
arr.first # 1
arr.last # 3
arr.at(1) # 2
# 修改
arr << 4 # 追加
arr.push(5) # 追加
arr.unshift(0) # 前置
arr.pop # 移除并返回最后一个
arr.shift # 移除并返回第一个
arr.delete_at(1) # 删除索引处
arr.delete(3) # 删除值
arr.insert(1, 'a') # 在索引处插入
# 组合
[1, 2] + [3, 4] # [1, 2, 3, 4]
[1, 2] * 2 # [1, 2, 1, 2]
[1, 2, 3] - [2] # [1, 3]
[1, 2] & [2, 3] # [2](交集)
[1, 2] | [2, 3] # [1, 2, 3](并集)
# 查询
arr.include?(2) # true
arr.empty? # false
arr.length # 3
arr.count # 3
arr.count(2) # 计数出现次数
# 转换
arr.reverse # [3, 2, 1]
arr.flatten # 展平嵌套数组
arr.compact # 移除nil
arr.uniq # 移除重复
arr.join(', ') # 转换为字符串
arr.sample # 随机元素
arr.shuffle # 随机顺序
哈希
# 创建
hash = { name: '爱丽丝', age: 30 }
hash = Hash.new(0) # 默认值0
hash = Hash.new { |h, k| h[k] = [] } # 默认块
# 访问
hash[:name] # '爱丽丝'
hash.fetch(:age) # 30
hash.fetch(:email, '不适用') # 带默认值
hash.dig(:person, :name) # 安全嵌套访问
# 修改
hash[:email] = '爱丽丝@example.com'
hash.delete(:age)
hash.merge!(other_hash)
hash.transform_keys(&:to_s)
hash.transform_values { |v| v.to_s }
# 迭代
hash.each { |key, value| puts "#{key}: #{value}" }
hash.each_key { |key| puts key }
hash.each_value { |value| puts value }
# 查询
hash.key?(:name) # true
hash.value?('爱丽丝') # true
hash.empty? # false
hash.size # 2
# 转换
hash.keys # [:name, :age]
hash.values # ['爱丽丝', 30]
hash.invert # 交换键和值
hash.select { |k, v| v.is_a?(String) }
hash.reject { |k, v| v.nil? }
hash.compact # 移除nil值
hash.slice(:name, :age) # 提取子集
字符串
str = "你好,世界!"
# 大小写
str.upcase # "你好,世界!"(注:中文无大小写变化,保持原样)
str.downcase # "你好,世界!"
str.capitalize # "你好,世界!"
str.swapcase # "你好,世界!"
str.titleize # 需要ActiveSupport
# 修剪
" 你好 ".strip # "你好"
" 你好 ".lstrip # "你好 "
" 你好 ".rstrip # " 你好"
# 搜索
str.include?("世界") # true
str.start_with?("你好") # true
str.end_with?("!") # true
str.index("世界") # 3
str.rindex("好") # 1
# 分割和连接
"a,b,c".split(",") # ["a", "b", "c"]
["a", "b", "c"].join("-") # "a-b-c"
# 替换
str.sub("世界", "Ruby") # 替换第一个
str.gsub("好", "0") # 替换所有
str.delete("好") # 移除字符
str.tr("aeiou", "12345") # 翻译字符(示例保持)
# 子字符串
str[0] # "你"
str[0..2] # "你好,"
str[3..] # "世界!"
str.slice(0, 2) # "你好"
# 查询
str.empty? # false
str.length # 5
str.size # 5
str.count("好") # 1
# 转换
"123".to_i # 123
"3.14".to_f # 3.14
:symbol.to_s # "symbol"
# 编码
str.encoding # #<Encoding:UTF-8>
str.force_encoding("ASCII")
str.encode("ISO-8859-1")
# 多行
text = <<~HEREDOC
这是一个
多行字符串
缩进已移除
HEREDOC
正则表达式
# 创建
regex = /pattern/
regex = Regexp.new("pattern")
# 匹配
"hello" =~ /ll/ # 2(索引)
"hello" !~ /zz/ # true
"hello".match(/l+/) # #<MatchData "ll">
"hello".match?(/l+/) # true(更快,无MatchData)
# 匹配数据
match = "hello123".match(/(\w+)(\d+)/)
match[0] # "hello123"(完全匹配)
match[1] # "hello"(第一组)
match[2] # "123"(第二组)
# 命名捕获
match = "hello123".match(/(?<word>\w+)(?<num>\d+)/)
match[:word] # "hello"
match[:num] # "123"
# 字符串方法带正则表达式
"hello world".scan(/\w+/) # ["hello", "world"]
"a1b2c3".scan(/\d/) # ["1", "2", "3"]
"hello".sub(/l/, 'L') # "heLlo"
"hello".gsub(/l/, 'L') # "heLLo"
"a:b:c".split(/:/) # ["a", "b", "c"]
# 标志
/pattern/i # 不区分大小写
/pattern/m # 多行
/pattern/x # 扩展(忽略空白)
# 常见模式
/\d+/ # 一个或多个数字
/\w+/ # 一个或多个单词字符
/\s+/ # 一个或多个空白字符
/^start/ # 字符串开始
/end$/ # 字符串结束
/[aeiou]/ # 字符类
/[^aeiou]/ # 否定类
/(cat|dog)/ # 交替
文件I/O
# 读取
content = File.read("文件.txt")
lines = File.readlines("文件.txt")
File.open("文件.txt", "r") do |file|
file.each_line do |line|
puts line
end
end
# 写入
File.write("文件.txt", "内容")
File.open("文件.txt", "w") do |file|
file.puts "第一行"
file.puts "第二行"
end
# 追加
File.open("文件.txt", "a") do |file|
file.puts "追加行"
end
# 文件模式
# "r" - 只读
# "w" - 写入(截断)
# "a" - 追加
# "r+" - 读取和写入
# "w+" - 读取和写入(截断)
# "a+" - 读取和追加
# 文件操作
File.exist?("文件.txt") # true/false
File.file?("文件.txt") # 是否是文件?
File.directory?("目录") # 是否是目录?
File.size("文件.txt") # 大小(字节)
File.mtime("文件.txt") # 修改时间
File.basename("/路径/到/文件.txt") # "文件.txt"
File.dirname("/路径/到/文件.txt") # "/路径/到"
File.extname("文件.txt") # ".txt"
File.join("路径", "到", "文件.txt") # "路径/到/文件.txt"
# 目录操作
Dir.entries(".") # 列出目录
Dir.glob("*.rb") # 模式匹配
Dir.glob("**/*.rb") # 递归
Dir.mkdir("新目录")
Dir.rmdir("旧目录")
Dir.pwd # 当前目录
Dir.chdir("/路径") # 更改目录
FileUtils.mkdir_p("a/b/c") # 创建嵌套目录
FileUtils.rm_rf("目录") # 递归移除
FileUtils.cp("源", "目标") # 复制文件
FileUtils.mv("源", "目标") # 移动文件
时间和日期
require 'time'
require 'date'
# 时间
now = Time.now
utc = Time.now.utc
local = Time.now.localtime
# 组件
now.year # 2024
now.month # 11
now.day # 25
now.hour # 14
now.min # 30
now.sec # 45
now.wday # 星期几(0=星期日)
# 创建
Time.new(2024, 11, 25, 14, 30, 45)
Time.parse("2024-11-25 14:30:45")
Time.at(1700000000) # 从Unix时间戳
# 格式化
now.strftime("%Y-%m-%d %H:%M:%S")
now.strftime("%B %d, %Y") # 十一月 25, 2024
now.iso8601 # ISO 8601格式
# 算术
now + 3600 # 添加1小时(秒)
now - 86400 # 减去1天
time2 - time1 # 差异(秒)
# 日期
date = Date.today
date = Date.new(2024, 11, 25)
date = Date.parse("2024-11-25")
date.year # 2024
date.month # 11
date.day # 25
date.wday # 1(星期一)
date + 7 # 添加7天
date - 7 # 减去7天
date.next_day # 明天
date.prev_day # 昨天
date.next_month # 下个月
date.prev_year # 去年
# DateTime(结合日期和时间)
dt = DateTime.now
dt = DateTime.parse("2024-11-25T14:30:45")
范围
# 包含
(1..5).to_a # [1, 2, 3, 4, 5]
# 排除
(1...5).to_a # [1, 2, 3, 4]
# 方法
(1..10).include?(5) # true
(1..10).cover?(5) # true(更快)
(1..10).member?(5) # true
(1..5).each { |n| puts n }
(1..5).map { |n| n * 2 }
# 字符串范围
('a'..'e').to_a # ["a", "b", "c", "d", "e"]
# case语句
case age
when 0..12
"儿童"
when 13..19
"青少年"
else
"成人"
end
集合
require 'set'
# 创建
set = Set.new([1, 2, 3])
set = Set[1, 2, 3]
# 操作
set.add(4)
set << 5
set.delete(3)
# 集合操作
set1 | set2 # 并集
set1 & set2 # 交集
set1 - set2 # 差集
set1 ^ set2 # 对称差集
# 查询
set.include?(2) # true
set.empty? # false
set.size # 3
# 子集/超集
set1.subset?(set2)
set1.superset?(set2)
最佳实践
- 使用Enumerable方法 而不是手动循环
- 链式方法 以提高可读性:
array.select(&:even?).map(&:to_s) - 使用符号到Proc(
&:method_name)当可能时 - 优先使用带块的File.open 以自动关闭文件
- 对哈希使用
fetch当你想处理缺失键时 - 利用惰性枚举 对于大型集合
- 使用
Pathname对于复杂路径操作
反模式
❌ 不要使用for循环 - 使用Enumerable方法
❌ 不要忘记关闭文件 - 使用带块的File.open
❌ 不要使用each进行转换 - 使用map
❌ 不要使用each进行过滤 - 使用select或reject
❌ 不要在迭代时修改数组 - 使用返回新数组的方法
相关技能
- ruby-oop - 用于理解核心类
- ruby-blocks-procs-lambdas - 用于使用Enumerable
- ruby-metaprogramming - 用于高级库用法