Ruby 数据类型

前一章学了"变量是装值的容器",这一章讲"容器里装什么"。Ruby 内置的数据类型不算多,但每个都有极其丰富的方法。本章先给个总览,后面会专门用整章讲字符串、数组、哈希三个最重要的。

1. 数值(Numeric)

Ruby 的数值分两大类:Integer(整数)Float(浮点数)。Ruby 2.4 之后不再分 FixnumBignum,统一用 Integer:

# 整数(Integer):不分 int/long,自动用大数
age = 25
year = 2026
big = 10 ** 20      # 大整数也自动支持
puts age.class      # Integer
puts big.class      # Integer

# 浮点数(Float)
pi = 3.14159
puts pi.class       # Float

# 整数除法 vs 浮点除法
puts 7 / 2          # 3(整数除整数,结果是整数,向下取整)
puts 7.0 / 2        # 3.5(其中一个为浮点,结果为浮点)
puts 7.fdiv(2)      # 3.5(强制浮点除法)

新手最易踩的坑是整数除法:7 / 2 得到 3(向下取整),不是 3.5。要浮点结果,把任一操作数写成浮点(7.0),或用 fdiv 方法。

2. 布尔值与 nil

Ruby 的真假对象是 true(TrueClass 的唯一实例)和 false(FalseClass 的唯一实例)。还有一个表示"无"的特殊对象 nil(NilClass 的唯一实例):

# true / false 是对象
puts true.class     # TrueClass
puts false.class    # FalseClass

# nil 表示"什么都没有",类似其他语言的 null
x = nil
puts x.class        # NilClass
puts x.nil?         # true
puts x.to_s         # ""(空字符串,Rails 还会把它显示成 "")
puts x || "默认值"  # 默认值(|| 短路求值是惯用法)

前面语法章提过:只有 nil 和 false 是假。所以 x || "默认值" 是 Ruby 里设置默认值的惯用法——当 x 是 nil 或 false 时用后面的值。

3. 字符串(String)

字符串是 Ruby 用得最多的类型。它分单引号双引号两种:

# 双引号:支持插值和转义
name = "小明"
puts "你好, #{name}"       # 你好, 小明
puts "行1\n行2"            # 换行(在反引号模板里要写 \n)

# 单引号:几乎不解析任何东西
puts '你好, #{name}'        # 你好, #{name}(原样输出)
puts '行1\n行2'            # 行1
行2(单引号里 \n 仍是字面)

# 字符串拼接
puts "a" + "b"             # ab
puts "a" * 3               # aaa(乘法重复)

差异在于:

实际项目里 95% 用双引号。单引号用在"字符串里有引号、且不需要插值"的场景,性能略快一点点(可忽略)。

4. 符号(Symbol)

符号是 Ruby 独有的一种类型,以冒号开头。它是不可变的、全局唯一的"标签":

# 符号(Symbol):轻量、不可变的"标签"
status = :active
puts status.class         # Symbol
puts status               # active
puts status.to_s          # "active"(转字符串)

# 符号 vs 字符串
puts :name.object_id      # 一个固定数字
puts :name.object_id      # 同样的数字(全局唯一)
puts "name".object_id     # 每次不同
puts "name".object_id     # 又一个不同数字

# 当键用,符号更快更省内存
config = { name: "小明", age: 18 }   # 等价于 { :name => "小明", :age => 18 }

核心区别:字符串每次创建都是新对象("name".object_id 每次不同),符号全局唯一(:name.object_id 永远相同)。所以当字典的键、当方法名、当状态标签用符号更省内存。Rails 里到处是 params[:id] 这种符号键。

新手口诀:内容用字符串,名字用符号

5. 数组(Array)

数组是有序集合,可以放任何类型的元素:

# 数组:有序集合,元素类型可以混合
nums = [1, 2, 3, 4, 5]
mixed = [1, "two", 3.0, :four]
empty = []

puts nums.class         # Array
puts nums.first         # 1
puts nums.last          # 5
puts nums[-1]           # 5(负索引从末尾数)
puts nums.length        # 5

# %w 快速生成字符串数组(单词数组)
words = %w[apple banana cherry]
puts words.inspect      # ["apple", "banana", "cherry"]

数组有非常非常丰富的方法——mapselectreducesorteach 等等。后面有专门一章讲。

6. 哈希(Hash)

哈希是键值对集合,类似 JS 的对象、Python 的 dict:

# 哈希:键值对
person = {
  name: "小明",
  age: 18,
  city: "北京"
}

puts person.class        # Hash
puts person[:name]       # 小明
puts person[:age]        # 18

# 老语法(Hash Rocket)
old = { :name => "小明", :age => 18 }
# 跟新语法等价,新手优先用新语法(name: 是 :name => 的简写)

新手最易混淆的是两种语法——新语法 name: value 实际上是 :name => value 的简写,只对全符号键有效。如果键不是符号(比如字符串键或数字键),只能用 Hash Rocket =>

7. 范围(Range)

范围表示一个区间,有两个点 ..(包含末尾)和三个点 ...(不含末尾):

# 范围(Range):表示一个区间
r1 = 1..5          # 包含末尾(1,2,3,4,5)
r2 = 1...5         # 不含末尾(1,2,3,4)

puts r1.to_a.inspect   # [1, 2, 3, 4, 5]
puts r2.to_a.inspect   # [1, 2, 3, 4]

# 常用于遍历和判断
(1..3).each { |i| puts i }
puts (1..10).include?(5)   # true
puts ('a'..'e').to_a.inspect

范围常用在 for 循环、case 分支、批量生成数据。Rails 的分页常用 Post.all[10..19] 取第 10 到 19 条。

8. 类型查询与转换

因为 Ruby 是动态类型,经常需要判断类型转换类型:

# 用 .class 查类型
puts 5.class            # Integer
puts "hi".class         # String
puts [].class           # Array
puts({}.class)          # Hash
puts :foo.class         # Symbol

# 用 is_a? 判断是否属于某类型(包括父类)
puts 5.is_a?(Integer)       # true
puts 5.is_a?(Numeric)       # true(Numeric 是 Integer 的父)
puts "hi".is_a?(String)     # true

# 类型转换
puts "42".to_i       # 42
puts 42.to_s         # "42"
puts "3.14".to_f     # 3.14
puts 0.to_s          # "0"

常用转换方法:to_i(转整数)、to_f(转浮点)、to_s(转字符串)、to_a(转数组)、to_h(转哈希)、to_sym(字符串转符号)。

9. 类型总览

小结

本章你浏览了 Ruby 的内置类型。数值、布尔、符号、范围相对简单;字符串、数组、哈希因为方法太多,后续各有一章专门讲。下一篇先看运算符——学会怎么操作这些数据。

← 上一篇 Ruby 变量

下一篇 Ruby 运算符

✈️💬