Posts 浅谈ruby中隐式、显式方法区别(to_s,to_str等)
Post
Cancel

浅谈ruby中隐式、显式方法区别(to_s,to_str等)

在ruby中,虽然不常见,但是有时候会看见类似to_str,to_ary,to_hash,to_int等方法,他们看起来跟我们常用的to_i,to_a等方法似乎是一样的功能,但是却明显感觉到他们是不一样的,这到底是为什么呢?这就是ruby中常用数据类型的隐式和显式方法了,所以这里简单谈谈ruby中数据类型的隐式、显式的功能和区别 想要进阶ruby,这个概念是一定要掌握以及使用的,有了它,你的代码就会有新的思考方向,有新的设计架构。这并不是一个很难的东西,慢慢的去品味它就能品出味道。

好了,开始!

不管任何语言,基础数据类型无外乎array,string,int,float,hash,date等类型,然后在这些数据类型的基础上再衍生出其他更复杂的数据类型。

看起来很像字符串的n

我们来看个例子

n = Time.now
=> 2019-10-15 17:43:48 +0800

设变量n,其值为当前的时间,我们看到n的值是2019-10-15 17:43:48 +0800,虽然看起来是一个字符串,但是其实并不是,n只是Time类的一个实例,也就是说n并不是String类的实例,这两个数据并不是一种数据,尽管他们看起来确实很像

n.is_a? String
=> false

可以看出确实n并不是String类,所以如果我们要对n进行操作,比如我们要:

m = "It is time: "
m + n

我们有个字符串m,我们想实现打印出类似”It is time: 2019-10-15 17:43:48 +0800”这样的数据,如果n也是字符串,这一点问题都没有,但是就是因为n并不是字符串,所以会直接报错:

1: from (irb):5:in `+'
TypeError (no implicit conversion of Time into String)

(请注意这个报错提示里面的implicit)

前面说了这么一大堆废话就是想引出隐式,显式的概念,在ruby里面有类似to_s,to_str,to_i,to_int,to_a,to_ary等方法,他们看起来实现的功能貌似是一样的,比如to_s和to_str方法,他们都是把对象字符串化,但是不同的地方就是to_s是显式,to_str是隐式的。这个概念其实我觉得比较晦涩,我们只能通过例子用更加通俗的大白话去形容和理解。

显式可以强制转换

还是前面的m + n为例,因为m是字符串,而n是一个Time类的实例,我们看起来2019-10-15 17:43:48 +0800这个东西虽然很像字符串,那只是我们站在人类的角度去理解的,但是计算机的角度,一个是Time类的实例,一个是String类的实例,两者根本就是风马牛不相及,你让他俩相加,必须得给你报错! 我们期望程序也能够有人类这种直觉怎么办呢?所以就有了隐式显式这个东西的引入。 我们先从显式说起,比如to_s就是显式方法,显式就是强制让两个不同类型的数据进行转化,从而达到让转化后的两个数据明显的不同,所以就叫做显式。一个非常非常实际的例子就是,假设一个整数143,我们想把这个整数去变成一个字符串,就是一个显式的变化。所以我们用143.to_s方法就可以得到字符串’143’,这就是一个强制性转化的显式应用。显式方法我们用的很多,但是很多人应该都不清楚这种处理其实是在做显式转化。比如前面我们用的Time.now其实不是字符类型,那么我们需要添加一个转化Time.now.to_s,两者结果虽然看起来是一模一样的,但是后者已经是一个彻底的字符类型了,很多对面向对象不熟悉的人在这方面一定会踩很多坑。

隐式的调用你看不到

说完常用的显式,我们再来讲很晦涩的隐式。其实通俗的理解就是,显式是两个数据明显非常不一样(再次强调要从计算机角度去理解这个不一样)你去转化,而隐式就是两个数据似乎有那么点联系,看起来好像是一样的,似乎还是很晦涩,没事还是用简单例子去理解。 前面我们用一个字符串m,去加一个Time类实例n,虽然结果直接报错了,但是其实程序内部还是做了努力的,它会努力的让这个表达式不报错,虽然这些我们看不到。 当用字符串m去加n的时候,程序会尝试去看看这个n是不是字符串,结果发现n不是字符串,然后程序并不会直接报错,它还会去尝试让n去尽量的变成字符串,这个过程就用到隐式变化,程序会去看n能不能隐式的变成字符串,也就是调用隐式的to_str方法(注意不是to_s,to_s是显式)。结果发现n并没有to_str的方法,所以程序觉得n实在是跟字符串差的太远了,宣告失败,报错!(所有程序报错是在做了一定努力以后在报错的,前面有提到报错提示里有implict字眼,就是程序在调用了to_str隐式方法做隐式转化后还失败后才报错的) 是的,看到这里应该就能知道,隐式变化的功能就是让数据在不直接显式改变数据类型的前提下,还能拥有原始数据类型的功能。所以我们只要在Time类里面定义一个to_str方法就能用m+n不报错了。因为就算n不是字符串,在计算的时候他也会会尝试隐式的字符串方法to_str.

坐标能和字符串相加吗?

如果还是不理解,那就只能再上一个例子了。

class Point
  def initialize(x,y)
    @x = x
    @y = y
  end

  def to_str
    @x.to_s + ',' + @y.to_s
  end
end

a = 'Point '
b = Point.new(1,2)

a + b

我们随便定义了一个类point,只定义了一个最简单的to_str方法来验证,我们可到看到,理论上我们这个带数字x,y坐标的类跟字符串根本是一点关系都没有,不可能两者能够相加,但是当我们运行a+b后,竟然没有报错,能够准确输出”Point1,2”。其根本原因,就是因为Point类里定义了隐式的to_str方法,使得point类的实例被程序看起来是一个类字符串,虽然并不是字符串类型,我们也没有直接强制显式的把它转换成字符串,但是它仍然可以安全,准确的和字符串进行运算。因为拥有隐式的方法,使得它就拥有了类字符串的功能。所以我们可以明白,程序并不会自主的去调用显式方法转换,因为显式转化的变化太大了,如果程序不经过程序员的同意就去调用显式转化的话,那就太不安全了,但是隐式的调用可以,它并不会改变数据结构,它会让数据拥有更安全的类似功能,比如类字符串,类数组,类哈希等等。这里面的一切,都是隐藏起来的,并不容易被发觉,所以如果处理不当,同时也会带来很难查找的bug,所以这是属于高级功能。只有当你很了解的情况下才需要使用这个功能。

本文仅仅抛砖引玉用字符串的显式、隐式转化浅谈程序设计中的功能实现,其他的to_ary,to_int,to_hash,to_regexp是一个道理,如果你理解隐式、显式的话,那一定会感觉多了把武器,在设计功能模块的时候能够游刃有余,显式让你拥有更多的灵活性,扩展性,隐式让你可以有更好的安全性,封闭性。具体的实际应用那就需要大家在实际的项目中多去思考和应用了。

OLDER POSTS NEWER POSTS

Comments powered by Disqus.

Contents

Search Results