[关闭]
@elibinary 2017-05-14T04:04:10.000000Z 字数 1292 阅读 1049

关于 Ruby 的类型转换

Ruby


在平时写代码的时候少不了要经常进行一些类型转换,经常性的要用到 #to_a, #to_s, #to_i 之类的方法,这些方法就是 ruby 标准类型的显式转换方法。

有显式转换,那么相对的也有隐式转换。在很多情况下,Ruby会隐式的在参数对象上调用隐式转换方法,以便得到预期的参数类型。举个例子:

  1. # String 的 + 运算符能够将多个字符串拼接成一个新字符串
  2. 'eli ' + 'zhang'
  3. #=> "eli zhang"
  4. # 那么当我要拼接的对象不是一个字符串对象呢
  5. 'eli ' + Time.now
  6. #=> TypeError: no implicit conversion of Time into String

当要使用 + 运算符来接受一个 Time 类型的参数时,报了 TypeError 的错。我们知道,ruby是动态类型语言,不会去做类型检查,那么这有是怎么给出的呢。
事实上 String#+ 方法通过隐式的调用 #to_str 方法来检测参数是不是类字符串的(可以看出,ruby 只关心你能不能 response 给定的方法,而不关心你到底是什么,ruby中处处都显露着这种思想),并且使用转换之后的值,如果参数对象不能 response #to_str 方法,变回抛出上面那个 error

事实上, String 是 Ruby 核心类中唯一实现了 #to_str 方法,并且 #to_str 只是简单的返回了字符串本身。 #to_str 方法存在的意义在于,因为许多 Ruby 核心库方法期望得到字符串参数输入,他们就通过在输入对象上隐式的调用 #to_str 方法来实现这种期望。

那么这其实同时也就意味着,我们可以把我们自定义的对象伪装成字符串对象,让 Ruby 核心库方法接受它,并把它转换为真正的字符串对象。

  1. class MyString
  2. def initialize(str)
  3. @str = str
  4. end
  5. def to_str
  6. "is #{@str}"
  7. end
  8. def to_s
  9. to_str
  10. end
  11. end
  12. 'eli ' + MyString.new('cool')
  13. #=> "eli is cool"

可以看出,这样是能够正常运行的。通过在自定义类中实现 #to_str 方法,来暗示此对象就是一个类字符串对象。

还有一个非常有趣的例子(例子来自[CONFIDENT RUBY])

  1. winners = ['Homestar', 'King of Town', 'Marzipan', 'Strongbad']
  2. Place = Struct.new(:index, :name, :prize)
  3. first = Place.new(0, 'first', 'PQg')
  4. second = Place.new(1, 'second', 'LA')
  5. third = Place.new(2, 'third', 'Bd')
  6. winners[first]
  7. #=> TypeError: no implicit conversion of Place into Integer
  8. class Place
  9. def to_int
  10. index
  11. end
  12. end
  13. winners[first]
  14. #=> "Homestar"

之所以可以这样用,是因为 Ruby 会自动在数组下标参数上调用 #to_int 方法,以便将其转换为 integer。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注