冒号和他的学生们(连载15)——数据类型

Normal 0

冒号和他的学生们

——程序员提高班纪事

 

  1. 数据类型

遵礼谓之劬,守法谓之固,此荒国之风也                        ——《荀悦·申鉴》

 

摘要:            关于数据类型

 

待教室平静下来,冒号再度开腔:“在谈论动态语言之前,最好先澄清一下它与动态类型语言之间的区别。”

叹号讶然道:“它们不是一回事吗?一直以为动态语言是动态类型语言的简称呢。”

“有亲戚之名,却无血缘之亲。名称上相似,加之动态语言绝大多数确是动态类型语言,造成混淆实属在所难免,但二者之间并无必然联系——动态语言不一定是动态类型语言,动态类型语言也不一定是动态语言。”冒号飞跑的舌头几乎绊蒜,同时把众人的脑子搅成了一锅粥。

见势不妙,冒号改用迂回战术:“我们不妨再谈开些,大家对数据类型是如何理解的?”

逗号随口道:“数据类型不就是数据的种类吗?”

众人暗笑:说了跟没说差不多。

冒号说道:“数据类型包含两个要素:一个是允许取值的集合,一个是允许参与的运算。例如int类型在Java中既定义了介于− 231  231 − 1之间的整数集合,也定义了该集合上的整数所能进行的运算。现在的问题是:数据类型的意义何在?”

句号回答:“限定一个变量的数据类型,就意味着限制了该变量的取值范围和所参与的运算,这从一定程度上保证了代码的安全性。”

冒号追问:“还有吗?”

句号略作思考后说:“用户自定义的数据类型,如C中的结构和Java中的类或接口,赋予数据以逻辑内涵,提高了代码的抽象性。”

“精辟!”冒号赞道,“数据类型既有针对机器的物理意义,又有针对人的逻辑意义。前者用于进行底层的内存分配和数值运算等,后者用于表达高层的逻辑概念。既然类型如此重要,类型检查就必不可少了。所谓动态类型语言Dynamic Typing Language),正是指类型检查发生在运行期间run-time)的语言。

“那静态类型语言Static Typing Language)自然是类型检查发生在编译期间compile-time)的语言咯。”引号接话道。

冒号回应:“一般的说法是这样,不过我更愿意将‘编译期间’四个字改为‘运行之前’,否则容易让人误解为静态类型语言一定是编译型语言Compiled Language)。”

问号问道:“是否可以这么说:静态类型语言需要变量申明,而动态类型语言则不需要?”

“这话只对了一半。”冒号评论,“动态类型语言固然不需要显式的变量申明(Explicit Declaration,一些静态类型语言有时也不需要。典型的如MLHaskell之类的函数式语言,编译器可以通过上下文来进行类型推断type inference)。”

叹号感慨:“动态类型语言不必申明变量,甚至一个变量在不同地方可以代表不同类型,多省事多方便啊!”

冒号微微颔首:“动态类型语言的确有简明快捷的优势,并且天然具有泛型(generic)特征,代码更加灵活。比如,动态类型有一种被称作鸭子类型Duck Typing)的形式。”

逗号感到有趣:“鸭子类型?很滑稽的名字。”

“这种类型的思想是:如果一个对象既会走鸭步又会呷呷叫,何妨将其视作鸭子呢?”冒号说着投影出一段Ruby代码——

class Duck                        #会叫会游的鸭

    def shout

        puts '呷呷呷'

    end

    def swim

        puts '鸭泳'

    end

end

 

class Frog                         #会叫会游的蛙

    def shout

        puts '呱呱呱'

    end

    def swim

       puts '蛙泳'

    end

end

 

def shoutAndSwim(duck)   #让一只会叫会游的家伙边叫边游

    duck.shout

    duck.swim

end

 

shoutAndSwim(Duck.new)   #让一只鸭边叫边游

shoutAndSwim(Frog.new)    #让一只蛙边叫边游

 

冒号继续讲解:“在SmalltalkPythonRuby等动态类型的OO语言中,只要一个类型具有shoutswim的方法,它就可以为shoutAndSwim所接受。在Java这种静态类型语言中是不可能的,除非鸭和蛙在同一继承树上,或者二者均显式实现了一个包含shoutswim的公用接口。”

句号敏锐地指出:“C++是静态类型语言,但它的模板也可实现类似功能,并不需要引入继承关系。”

“非常正确!但请接着看下去。”冒号又放出一段投影——

class Cock                                 #会叫不会游的鸡

    def shout

        puts '喔喔喔'

    end

end

 

class Fish                               #会游不会叫的鱼

    def swim

        puts '自由泳'

    end

end

 

def shoutOrSwim(duck, flag)   #让一只会叫或会游的家伙叫或游

    flag ? duck.shout : duck.swim

end

 

shoutOrSwim(Cock.new, true)       #让一只鸡叫

shoutOrSwim(Fish.new, false)       #让一只鱼游

 

“这里鸡没有swim的方法,鱼没有shout的方法。若采用C++的模板,shoutOrSwim是无法通过编译的。但在支持Duck 类型的语言中,只要在运行期间不让鸡swim、让鱼shout——除非你突发奇想——一切平安无事。”冒号作了个OK的手势。

“动态类型语言真是越看越可爱。”叹号简直垂涎欲滴了。

Duck类型为软件重用开启了新的窗口,但凡事都是一分为二的。由于Duck类型的接口组合是隐性的,其使用者需要比普通Interface更小心以避免误用;其维护者也需要更小心以避免破坏客户代码;此外它也可能造成滥用——将会叫会游的东西放进池塘似乎不算坏主意,但如果一艘轮船趁机也开了进来,恐怕就不那么美妙了。”

众皆莞尔。

“再来看看静态类型语言的好处“当然静态类型语言也有其优势:由于在运行之前进行了类型检查,一方面代码的可靠性增强,另一方面编译器有可能藉此优化机器代码以提高运行效率,同时相比前者节省了运行期的类型检查时间。此外,变量类型的声明表明了编程者的意图,有辅助文档的功效。”冒号解释着,“两种类型的体制可以用两种法律原则来类比:静态类型检查类似‘疑罪从有’的有罪推定制——在被证明合法之前是非法的,动态类型检查类似‘疑罪从无’的无罪推定制——在被证明非法之前是合法的至于如何取舍,套用一句话:‘Static Typing Where Possible, Dynamic Typing When Needed’。”

问号提出新问题:“动态类型语言与弱类型语言有何不同?”

冒号喟言:“它们也常常被混为一谈,但类型的动静与强弱完全是正交的两个概念。前者以类型的绑定(binding)时间来划分,后者以类型的刚性强度来划分。通常弱类型语言Weakly-typing Language)允许一种类型的值隐性转化为另一种类型,而强类型语言Strongly-typed Language)则不允许。举个例子,1"2"VB中等于3——第二个字符串转化为整数;在Javascript中等于"12"——第一个整数转化为字符串;在C中则等于一个不定的整数值——第二个字符串作为地址来运算。这样似乎很有趣很方便,但程序容易藏污纳垢,滋生臭虫(bug)。”

引号想起:“好像还有一种所谓的类型安全语言?”

逗号紧紧抱着头,仿佛害怕裂开。

“类型按安全性来划分,可分为类型安全语言(Type-safe Language)和类型不安全语言(Type-unsafe Language)。一般认为强类型语言是类型安全的,弱类型语言是类型不安全的。” 冒号应道,“至此,我们已论及数据类型的三种划分方式。值得一提的是,这些划分并非泾渭分明的,更多的是定性而非定量的描述,甚至没有公认统一的定义。但了解它们,对我们日后的学习是有所裨益的。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14674535/viewspace-374646/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14674535/viewspace-374646/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值