ruby中to_s和to_str、to_i和to_int、to_a和to_ary、to_h和to_hash的解释说明
包括to_s
和to_str
、to_i
和to_int
、to_a
和to_ary
、to_h
和to_hash
。统称为to_x
和to_xxx
。
那么,to_x
和to_xxx
的区别是什么,什么时候使用to_x
,什么时候使用to_xxx
。
解释
使用鸭子模型来解释比较容易点。
只要像鸭子,就能当成鸭子,这就是to_x
。只有它真的是鸭子,才能当成鸭子,这就是to_xxx
。
以to_s
和to_str
为例。
所有对象都能使用to_s
方法,用来将对象以字符串的格式去描述、去输出。也就是说,所有对象都能使用字符串的描述格式。
# 任意对象都能直接使用to_s()去描述自身
>> Object.new.to_s
=> "#<Object:0x00000002272e58>"
# 数值类中重写了to_s(),使之转换成字符串格式的数值描述形式
>> 1.to_s
=> "1"
只有真的是字符串的对象,或者能完全扮演字符串的对象,才有必要去使用to_str
。例如,String类自身、String类的某些子类,它们是真的鸭子,并不是简单的像鸭子。也就是说,只有严格符合鸭子要求的类型,才可以考虑去定义to_str
。
再严格一点,当某个地方能使用String类对象的时候,也一定能使用某类对象时(比如String的部分子类),这类对象就可以考虑去使用to_str
。
>> 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_xxx
。
to_i
和to_int
、to_a
和to_ary
、to_h
和to_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_a
和to_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_i
和to_int
都定义了。
>> a=3.5
>> a.class # => Float
>> a.to_i # => 3
>> a.to_int # => 3
结论
分为两种情况:什么时候调用to_x
和to_xxx
,以及什么时候在自己的类中实现to_x
和to_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
ruby中to_s和to_str、to_i和to_int、to_a和to_ary、to_h和to_hash的解释说明的更多相关文章
- 在 Ruby 中执行 Shell 命令的 6 种方法
我们时常会与操作系统交互或在 Ruby 中执行 Shell 命令.Ruby为我们提供了完成该任务的诸多方法. Exec Kernel#exec 通过执行给定的命令来替换当前进程,例如: $ irb & ...
- ruby中的整数、浮点数、字符串之间的相互转换
D:\learnProg\Ruby>irb#浮点数转换成整数,会强行去掉小数点后面的数字 irb(main):017:0> 123.45.to_i => 123 #整数转换成浮点数, ...
- Ruby中Block, Proc, 和Lambda
Block Blocks就是存放一些可以被执行的代码的块,通常用do...end 或者 {}表示 例如: [1, 2, 3].each do |num| puts num end [1, 2, 3]. ...
- ruby中symbol
Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字. 创建一个 Symb ...
- [Ruby学习总结]Ruby中的类
1.类名的定义以大写字母开头,单词首字母大写,不用"_"分隔 2.实例化对象的时候调用new方法,实际上调用的是类里边的initialize方法,是ruby类的初始化方法,功能等同 ...
- ruby中的链式访问和方法嵌套
先看一道题,这道题是codewars上的一道题,我很早就看到了,但是不会写.等到又看到这道题的时候,我刚看完元编程那本书,觉得是可以搞定它的时候了.废话不多说,先看这道题,题目最开始是为JavaScr ...
- 谈谈Ruby中的类变量
Ruby中的类变量,很多文章都是不太建议使用的,主要原因在于他的一些特性容易导致犯一些错误,尤其在广泛使用元编程的时候. 初步接触类变量可能觉得他跟C++的类静态成员和Java中的静态变量没什么区别, ...
- [翻译]理解Ruby中的blocks,Procs和lambda
原文出处:Understanding Ruby Blocks, Procs and Lambdas blocks,Procs和lambda(在编程领域被称为闭包)是Ruby中很强大的特性,也是最容易引 ...
- 理解Ruby中的作用域
作用域对于Ruby以及其它编程语言都是一个需要理解的至关重要的基础知识.在我刚开始学习ruby的时候遇到很多诸如变量未定义.变量没有正确赋值之类的问题,归根结底是因为自己对于ruby作用域的了解不够, ...
随机推荐
- box-shadow 画叮当猫
值 描述 h-shadow 必需.水平阴影的位置.允许负值 v-shadow 必需.垂直阴影的位置.允许负值 blur 可选.模糊距离 spread 可选.阴影的尺寸 color 可选.阴影的颜色.请 ...
- leetcode-只出现一次的数字合并两个有序数组
题目:合并两个有序数组 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明: 初始化 nums1 和 nums2 的元素 ...
- 继承ipkPlayer中出现的一些错误汇总
1.下载完ffmpeg后,我们再在终端执行下面两个命令: cd ios./compile-ffmpeg.sh clean./compile-ffmpeg.sh all 大体流程如下 这里如果出现 x ...
- laravel-elasticsearch 全文搜索设置
1.首先安装 jave环境 jdk 下载地址 ,我用的是最新版本的,有时版本要跟elasticsearch对应 2.安装elasticsearch 下载地址 3.安装Laravel scout 全文搜 ...
- SQL Server Service Broker创建单个数据库会话(消息队列)
概述 SQL Server Service Broker 用来创建用于交换消息的会话.消息在目标和发起方这两个端点之间进行交换.消息用于传输数据和触发消息收到时的处理过程.目标和发起方既可以在同一数据 ...
- CSS怎么在项目里引入自定义字体(@font-face)
前言: 以前我一直用内置的默认字体给文字设置字体,直到一天UI妹纸给了我下面的字体 当时我是蒙蔽的,这个字体的效果如下 默认字体并无该字体,直接设置是没有效果的,这时就需要用到自定义字体了 下面 ...
- [Swift]LeetCode998. 最大二叉树 II | Maximum Binary Tree II
We are given the root node of a maximum tree: a tree where every node has a value greater than any o ...
- [Swift]LeetCode1004. 最大连续1的个数 III | Max Consecutive Ones III
Given an array A of 0s and 1s, we may change up to K values from 0 to 1. Return the length of the lo ...
- 为什么公司宁愿 25K 重新招人,也不给你加到 20K?原因太现实……
年底了,还有几天就要过年了,年后必定又是一波跳槽季,我们为什么要跳槽,为什么公司不能满足我们加薪的需求? 说到这个话题,想必从事码农的各位都清楚的一个道理:工资都是跳出来的,其他行业我不太清楚,但在 ...
- 英语笔记3(git)
备注 一: Staging Modified Files Let’s change a file that was already tracked. (tracked 表示该文件已经被git管理过,再 ...