Ruby 中的数据类型

数据类型

就和几乎所有语言一样,Ruby也定义了几种基础的数据类型,它们分别是

  • Numeric
  • String

1 Numeric

Numeric类用来表示数字,其中又包含了IntegerFloatComplexBigDecimalRational共 5 个子类。

在日常开发中,IntegerFloat类使用的较多。

1.1 Integer

一个Integer类的对象就是一串数字,当该值的范围超过2^32时,该值将被透明的转化为Bignum类对象,反之则被转化为Fixnum类对象。
在开发过程中,我们可以使用千分符使数值更具有可读性,如:

1
100_00

与其他语言相同,当一个数值以 0 开头且长度不小于 2 位时,它将不会被当做十进制处理。同样,我们可以使用 0x 开头来表示十六进制数,如:

1
0xFF

1.2 Float

Ruby中使用浮点数其实与其他动态语言中并没有太大的区别,不过需要注意的是,Ruby并不支持缩写,如.1,我们必须完整的写作0.1

1.3 运算

Numeric类的运算规则遵循数学中的规则,但相比其他语言,Ruby还提供了一个非常便捷的指数运算:

1
2**10    # => 1024

当然,Ruby中也存在着一些意外的规则。
不同数据类型的溢出规则
Interger在运算后会对大数进行转化(Bignum),因此Integer不会产生溢出。但这一点在Float上却并不适用,当数据超出范围后它会溢出为Infinity/-Infinity/0三种情况。

1
2
3
4
2.6.5 :006 > (2**1024)
=> 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
2.6.5 :007 > (2**1024).to_f
=> Infinity

不同数据类型的除法
Integer的除法运算中,当除数为 0 时,会抛出ZeroDivisionError异常(我通常使用这种方式来刻意触发异常)、而在Float的除法运算中,除数为 0 时会返回Infintiy/-Infintiy。当然,这里也有一个例外,当发生0.0/0.0的运算时,会返回NaNnot a number

1
2
3
4
5
6
7
8
9
10
11
12
2.6.5 :011 > 1/0
Traceback (most recent call last):
5: from /usr/local/rvm/rubies/ruby-2.6.5/bin/irb:23:in`<main>'
4: from /usr/local/rvm/rubies/ruby-2.6.5/bin/irb:23:in`load'
3: from /usr/local/rvm/rubies/ruby-2.6.5/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in`<top (required)>'
2: from (irb):11
1: from (irb):11:in`/'
ZeroDivisionError (divided by 0)
2.6.5 :012 > 1.0/0
=> Infinity
2.6.5 :013 > 0.0/0.0
=> NaN

取余操作和除法
当有以下操作时,我们很容易得出结论为 2

1
7/3

当上述除数为负数时,在大部分语言里,我们都会得到-2 的结论,然而当我们在irb中输入表达式的时候却发现得到的结果是-3。这是因为Ruby在对负数做除法时时是向负无穷大取整的。
由此我们很容易推导得到一个结论:

1
-(a/b) != a/(-b)

指数操作的运算顺序
指数操作的计算顺序为从右向左,如:

1
2 ** 2 ** 3 == 2 ** 8 == 256 != 4 ** 3

2 String

Ruby中每次使用字符串字面量时,实则都会创建一个新的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
2.6.5 :004 > 3.times{puts 'hello'.object_id}
12676760
12676700
12676640
=> 3

2.6.5 :006 > str = 'hello'
=> "hello"
2.6.5 :007 > 3.times{puts str.object_id}
12681240
12681240
12681240
=> 3

需要注意的一点是,字符串的加法运算并不会将右侧操作数转化为字符串,因此在使用过程中需要手动转化,如

1
2
3
4
5
6
7
8
9
10
2.6.5 :001 > '111' + 2
Traceback (most recent call last):
5: from /usr/local/rvm/rubies/ruby-2.6.5/bin/irb:23:in`<main>'
4: from /usr/local/rvm/rubies/ruby-2.6.5/bin/irb:23:in`load'
3: from /usr/local/rvm/rubies/ruby-2.6.5/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in`<top (required)>'
2: from (irb):1
1: from (irb):1:in`+'
TypeError (no implicit conversion of Integer into String)
2.6.5 :002 > '111' + 2.to_s
=> "1112"

当然,在使用字符串内插操作时,转化是自动的

1
2
2.6.5 :003 > "1 + 1 = #{2}"
=> "1 + 1 = 2"

另外一个非常有趣的细节是当使用<<操作符对字符串进行追加,且被追加的内容是一个数字时,该数值会被按照ASCII码转移为字符,如

1
2
3
4
str = "a"
=> "a"
2.6.5 :005 > str << 97
=> "aa"