Ruby中to_s和to_str、to_i和to_int、to_a和to_ary、to_h和to_hash的解释说明

包括to_sto_strto_ito_intto_ato_aryto_hto_hash。统称为to_xto_xxx程序员

那么,to_xto_xxx的区别是什么,何时使用to_x,何时使用to_xxx数组

解释

使用鸭子模型来解释比较容易点。安全

只要像鸭子,就能当成鸭子,这就是to_x。只有它真的是鸭子,才能当成鸭子,这就是to_xxxruby

to_sto_str为例。设计

全部对象都能使用to_s方法,用来将对象以字符串的格式去描述、去输出。也就是说,全部对象都能使用字符串的描述格式。code

# 任意对象都能直接使用to_s()去描述自身
>> Object.new.to_s
=> "#<Object:0x00000002272e58>"

# 数值类中重写了to_s(),使之转换成字符串格式的数值描述形式
>> 1.to_s
=> "1"

只有真的是字符串的对象,或者能彻底扮演字符串的对象,才有必要去使用to_str。例如,String类自身、String类的某些子类,它们是真的鸭子,并非简单的像鸭子。也就是说,只有严格符合鸭子要求的类型,才能够考虑去定义to_str对象

再严格一点,当某个地方能使用String类对象的时候,也必定能使用某类对象时(好比String的部分子类),这类对象就能够考虑去使用to_strblog

>> 1.to_str
NoMethodError: undefined method `to_str' for 1:Fixnum
>> Object.new.to_str
NoMethodError: undefined method `to_str' for #<Object:0x00000002267648>

或者说,to_x是输出出来给人读的,to_xxx是让程序健壮的,让你在不理解的状况下别乱定义to_xxxci

to_ito_intto_ato_aryto_hto_hash也都同样,to_x是宽泛程度的数据类型转换,to_xxx是严格的、必须知道是干什么的时候才进行的数据类型转换。字符串

示例分析

例如:

>> [1, 2].join(',')
=> "1,2"
>> [1, 2].join(1)
TypeError: no implicit conversion of Fixnum into String

数组的join()方法用来将数组转换成字符串,且使用链接字符进行链接。也就是说,数组中的每一个元素以及链接符自身都得转换成字符串,才能保证转换的结果是字符串。

对于数组自身而言,调用to_s()便可将其内全部元素转换成字符串格式,可是链接符不能随便转换,只有那些可以做为链接符的类型才能转换,例如这里的数值1不能做为链接符,因此应当让链接符的转换过程使用to_str(),保证程序的健壮性、安全性。固然,若是你认为1也能够做为链接符,你能够在设计join()程序的时候,经过to_s()去转换这里的数值1,但关键是join()不是你写的,而是别人写的,别人这么写有他本身的考虑。

再例如to_ato_ary,将hash结构转换成array:

>> {a: 10}.to_a
=> [[:a, 10]]

>> {a: 10}.to_ary
NoMethodError: undefined method `to_ary' for {:a=>10}:Hash
Did you mean?  to_a

上面第一个转换能成功。由于写hash类型的程序员认为,hash能够以一种方式转换成数组类型,因而它在hash类中定义了to_a()。这个转换并不影响大局,仅仅只是实现一个简单的功能而已。

to_ary()转换失败,由于hash是hash,array是array,在能使用array的地方,不表明能使用hash,假如在hash中定义了to_ary,那么在很大意义上就意味着hash和array在不少地方能够互换使用(特指hash能替代array),也就是能使用array的地方极可能也应该容许它使用hash。固然,仅仅只是意义上的替换,而非真正的能替换,但这极可能会牵一发而动全身。

再例如,浮点数确定可使用to_i简单转化成整数类型,但它应该定义to_int()吗?若是编写Float类的程序员认为,浮点数就是浮点数,毫不能当成int对象,那么他就要保证float对象不能转换成int,这时就不要定义to_int。但若是他认为浮点数做为一种int使用,那么就应该定义to_int。事实上,Float类中to_ito_int都定义了。

>> a=3.5
>> a.class   # => Float

>> a.to_i    # => 3
>> a.to_int  # => 3

结论

分为两种状况:何时调用to_xto_xxx,以及何时在本身的类中实现to_xto_xxx

  • 何时调用的问题
    • 调用to_x来将你的类作个宽松的类型转换
    • 调用Cls.to_xxx(arg)来验证arg真的能充当Cls使用
  • 何时实现的问题
    • 实现to_x,只要你认为能够按照你的观点转换将你的类转换成某个类型
    • 实现Cls.to_xxx(arg),只有当前想要保证某arg对象真的能够充当Cls时定义

最后,基本上全部类均可以按照你本身的想法去定义to_x,可是不多定义to_xxx,除非你真的知道本身在干什么,知道这会形成什么结果

参考连接:to_s vs. to_str (and to_i/to_a/to_h vs. to_int/to_ary/to_hash) in Ruby

相关文章
相关标签/搜索