静态类型和动态类型的优缺点
给男宝宝取名字静态类型和动态类型的优缺点上海景点排名
静态类型和动态类型的优缺点静态类型的优点下⾯列出了静态类型的主要优点:(1)静态类型可以在程序运⾏之前,依赖其与⽣俱来的限制来及早发现⼀些类型错误。(或是在插⼊/更新记录,解析XML⽂档等情况下进⾏检测。)(2)静态类型有更多机会(或者说更容易)优化性能。例如只要数据模型完整丰富,那么实现智能化的数据库索引就会更容易⼀些。编译器在拥有更精确的变量和表达式类型信息的情况下可以做出更优的决策。(3)在C++和Java这样拥有复杂类型系统的语⾔⾥,你可以直接通过查看代码来确定变量、表达式、操作符和函数的静态类型。这种优势或许在ML和Haskell这样的类型推导语⾔⾥并不明显,他们显然认为到哪⾥都要带着类型标签是缺点。不过你还是可以在有助阅读理解的情况下标明类型⼀⽽这些在绝⼤多数动态语⾔⾥是根本做不到的。(4)静态类型标注可以简化特定类型的代码⾃动化处理。⽐如说⾃动化⽂档⽣成、语法⾼亮和对齐、依赖分析、风格检查等各种“让代码去解读代码”的⼯作。换句话说,静态类型标签让那些类似编译器的⼯具更容易施展拳脚:词法⼯具会有更多明确的语法元素,语义分析时也⽐较少要⽤猜的。(5)只要看到API或是数据库结构(⽽不⽤去看代码实现或数据库表)就能⼤致把握到它的结构和⽤法。还有其他要补充的吗?继承者们结局
静态类型的缺点如下:(1)它们⼈为地限制了你的表达能⼒。⽐如,Java的类型系统⾥没有操作符重载、多重继承、mix-in、引⽤参数、函数也不是⼀等公民。原本利⽤这些技术可以做出很⾃然的设计,现在却不得不去迁就java的类型系统。⽆论是Ada还是C++,或是OCaml 等任何⼀种静态类型系统都有
这样的问题。差不多半数的设计模式(不光是Gof的那些)都是扭曲原本⾃然直观的设计,好将它们塞进某种静态类型系统:这根本就是⽅枘圆凿嘛。(2)它们会拖慢开发进度。事先要创建很多静态模型(⾃顶向下的设计),然后还要依据需求变化不断修改。这些类型标注还会让源代码规模膨胀导致代码难以理解,维护成本上升。(这个问题只在Java⾥⽐较严重,因为它不⽀持给类型取别名。)还有就是我上⾯已经提到过的,你得花更多的时间来调整设计,以适应静态类型系统。(3)学习曲线⽐较陡。动态类型语⾔⽐较好学。静态类型系统则相对挑剔,你必须花很多时间去学它们建模的⽅式,外加静态类型的语法规则。另外,静态类型错误(也可以叫编译器错误)对于初学者来说很难懂,因为那时程序根本还没跑起来呢。你连⽤printf来调试的机会都没有,只能撞⼤运似的调整代码,祈求能让编译器满意。因此学习C++⽐C和Smalltalk难,OCaml⽐Lisp难,Nice语⾔⽐Java难。⽽Perl所具备的⼀系列静态复杂性—各种诡异的规则,怎么⽤,什么时候⽤等—让它的难度⽐Ruby和Python都要⾼。我从来没见过有哪门静态类型语是很好学的。(4)它们会带来虚幻的安全感。静态类型系统确实能减少运⾏时的错误,提升数据的完整性,所以很容易误导⼈们觉得只要能通过编译让程序跑起来,那它基本上就没什么bug了。⼈们在⽤强静态类型系统的语⾔写程序时似乎很少依赖单元测试,当然这也可能只是我的想像罢了。(5)它们会导致⽂档质量下滑。很多⼈觉得⾃动⽣成的javadoc就⾜够了,哪怕不注释代码也没关系, Sourceforge 上充斥着这样的项⽬,甚⾄连Sun JDK 也常常有这个问题。(⽐如,Sun很多时候都没有给static final常量添加javadoc注释。)(6)很难⽤它们写出兼具⾼度动态和反射特点的系统。绝⼤多数静态类型语⾔(⼤概)都出于追求性能的⽬的,拟声
梦见还钱
新婚姻法婚前财产在运⾏时丢弃了⼏乎所有编译器⽣成的元数据。可是这样⼀来这些系统通常也就很难在运⾏时作出修改(甚⾄连内省都做不到)⽐如,若要想给模块加⼀个新函数,或是在类⾥加个⽅法,除了重新编译,关闭程序然后重启之外别⽆他法。受此影响的不单是开发流程整个设计理念也难逃波及。你可能需要搭建个复杂的架构来⽀持动态功能⽽这些东西会⽆可避免地和你的业务代码混在⼀起。
动态类型的优缺点:只要把上⾯的列表对调⼀下,你基本上就可以列出动态类型语⾔的优缺点了。动态语⾔的表达能⼒更强,设计灵活度也更⼤;易学易⽤,开发速度快;通常运⾏时的灵活性也更⾼。相对地,动态语⾔⽆法及时给出类型错误(⾄少编译器做不到),性能调优的难度也⽐较⾼,很难做⾃动化静态分析,另外,变量和表达式的类型在代码⾥很不直观,没办法⼀眼看出来。静态语⾔最终会向⽤户屈服开始添加⼀些动态特性,⽽动态语⾔常常也会尝试引⼊⼀下可选的静态类型系统(或是静态分析⼯具),此外它们还会设法改善性能增加错误检测,以便及早发现问题。很遗憾,除⾮⼀开始设计语⾔的时候就考虑到可选的静态类型,否则强扭的⽠怎么也不会甜的。
强类型与弱类型系统的较量下⾯我会以稍微有点戏谑的⽅式解释这两种理念(指的是强类型和弱类型)的⼯作流程,尽可能将它们本质区别展现出来。强类型阵营基本是这样⼯作的:⾸先是按照当前的需求进⾏设计;制定出⽂档哪怕只是初稿也没关系;然后定义接⼝和数据模型。假设系统要承受巨⼤流量,因此每个地⽅都要考虑性能。避免采⽤垃圾收集和正则表达式这类抽象。(注意:即便是Java程序员,通常也会努⼒避免触发垃圾收集,他们总是在开始写程序之讨论对象池的问题。)他们
只有在⽆计可施的情况下才会考虑动态类型。例如,⼀⽀采⽤Corba的团队只有在极端情况下才会在每个接⼝调⽤上添加⼀个XML字符串参数,这样他们就能绕开当初选择的死板的类型系统了。
第⼆个阵营基本是这样⼯作的:先搭建原型。只要你写代码的速度⽐写同等详细程度的⽂档快,你就可以更早地从⽤户那⾥获得反馈。按照当下的需求定义合理的接⼝和数据模型,但是别在上⾯浪费太多时间。⼀切以能跑起来为准,怎么⽅便怎么来。假设⾃⼰肯定要⾯对⼤量的需求变化,所以每个地⽅⾸先考虑的是尽快让系统运⾏起来。能⽤抽象的地⽅就尽量⽤(⽐如如每次都去收集数据⽽先不考虑缓冲,能⽤正则的地⽅就先不⽤字符串⽐较)就算明明知是⽜⼑也没关系,因为你换回的是更⼤的灵活性。代码量⽐较少,通常bug的数量也会更少。他们只有在被逼⽆奈的情况下才会进⾏性能调优以及禁⽌修改接⼝和数据定义。例如,⼀⽀Perl团队可能会将⼀些关键的核⼼模块⽤C重写,然后创建XS绑定。时间—长,这些抽象就渐渐变成了既定标准,它们被包裹在数据定义和细致的OO接⼝⾥,再也⽆法修改。(就算是Perl 程序员也常常会忍不住祭出银弹,为常⽤的抽象编写OO接⼝)那你觉得最终采⽤这些策略的结果会怎么样?
设计模式不过现在⼤家都清醒过来了,不是吗?设计模式不是特性。⼯⼚不是特性,委托、代理、桥接也都不是。它们只是提供了漂亮的盒⼦,以松散的⽅式来装载特性。但是别忘了,盒⼦、袋⼦和隔板⾃⼰也是要占⽤空间的。设计模式也不例外(⾄少在“四⼈帮”的书⾥所介绍的⼤多数模式都是这样)。更悲剧的是“四⼈帮”模式⾥唯⼀能精简代码的解释器(Interpreter)模式却被那些恨不得把设计
模式纹在⾝上的程序员忽略了。依赖注⼊是另⼀个新型的Java设计模式,Ruby、Python、Perl还有Javascript,程序员⼤概听都没听过吧。就算他们听过,他们也能正确地得出他们根本不需要这种玩意⼉的结论。依赖注⼊是⼀种惊⼈的描述式架构,让Java能在某些⽅⾯和更⾼级的语⾔⼀样,变得更动态⼀点。你猜得没错,依赖注⼊会让Java代码变得更⼤。变⼤是Java中⽆法回避的东西。成长是⽣活的⼀部分。Java就像是俄罗斯⽅块,不过积⽊和积⽊之间的空隙都填不满,结果只能越堆越⾼。 me:现在Java程序员相信都知道依赖注⼊了,因为它太重要了,⽤在各⼤框架⾥,⽐如spring,依赖注⼊使得能够在⽂件⾥配置类及其各种关系,当然使得Java更灵活更强⼤了。程序员需要了解的是哪些数学分⽀?实际⽣活中,计算机科学家常⽤的数学和上⾯那个列表⼏乎没有重叠。其⼀,⼩学和中学⾥教的绝⼤部分数学都是连续的,也就是实数上的数学。⽽对计算机科学家来说,95%有趣的数学都是离散的,也就是整数上的数学。 me:程序员所要解决的数学问题⼀般都是离散数学,其中最有⽤的课程应该就是组合数学和概率论统计。除了概率论和离散数学,其他数学分⽀也是有助于程序员的。可惜除⾮你去辅修数学,否则学校是不会教你的。它们包含了:(1)统计。我的离散数学书⾥讲到了⼀点。但是统计是⼀门完整的学科,⽽且是⾮常重要的学科,重要到根本不需要额外介绍。(2)代数和线性代数(⽐如矩阵)。线性代数应该紧跟在代数后⾯教。它不是很难,⽽且在很多领域都⾮常⾮常有⽤,⽐如机器学习。(3)数理逻辑。(4)信息论和柯⽒复杂度。信息论(粗略地讲)主要是关于数据压缩的,⽽柯⽒复杂度(同样粗略地讲)则是关于算法的复杂度(⽐如最⼩空间是多少,需要多长时间,程序或者数据结构有多优雅等)的。它们都是好玩,有趣,实⽤的学科。当
然还有其他的分⽀,⽽且有些学科互有重叠。但重点在于:对你有⽤的数学和学校觉得有⽤的数学是⾮常不同的。微积分的本质就是连续⼀变化的速度,曲线下的⾯积,固体的体积。很有⽤,记忆和很多烦琐的步骤程序员通常不需要这些东西。知道⼤致概
但是需要⼤量的概念和技巧就可以了,细节⽅⾯等到需要的时候再查也来得及。编译器,你懂吗?我在招⼈的时候有⼀个诀窍。就是在寻优秀的软件⼯程师“通才”的时候,通常在简历上你可以看到到各种让你觉得不⾏的关键字和词,但“编译器”是我唯⼀感兴趣的词。 me:作者强烈要求程序员学编译器原理,你还记得吗?编译器会接收⼀串符号流,根据预先定义好的规则,分析出这串符号的结构,然后把它转换成另⼀串符号流。是不是很笼统?的确是。⼀幅图⽚能不能被当成是符号流?当然可以。它可以是每⼀⾏像素所组成的流。每个像素就是⼀个数字。每个数字就是⼀个符号。编译器当然可以转换图⽚。英语可以被当做符号流叫吗?当然可以。规则或许会很复杂,但是⾃然语⾔处理的确可以被看成是某种很炫的编译。编译过程中第⼀个⼤阶段就是解析,即把输⼊的内容变成⼀棵树。中间要经过预处理,词法分析(也叫单词化)然后是语法分析和中间代码⽣成这⼏个步骤。词法分析通常是由正则表达式来完成的。语法分析则是根据语法完成。你可以采递归向下(最常见)或是解析器⽣成器(在⼩语⾔中⽐较常见)或是更炫的算来实现,只不过相应的执⾏速度也会慢⼀点。⽆论如何,最后的结果通常都是某解析树。第⼆个⼤阶段是类型检查。这是⼀狂热的学术分⼦(包括他们的组织以及或者⼿下的研究⽣)他们⾃信可以写出⾮常聪明的程序,能分析出你的程序想⼲什么,并
且在你出错的时候帮你指出。不过奇怪的是,他们并不觉得⾃⼰是在研究⼈⼯智能毕竟⼈⼯智能界已经(明智地)放弃确定性的⽅法了。第三个阵营是代码⽣成,他们通常都被边缘化了。只要你对递归有⾜够的了解,知道⾃⼰的祖先不是亚当和夏娃,那么代码⽣成还是挺直观的。这⾥要讲的其实是优化就是那种⽣成⾜够正确的代码,让绝⼤多数⽤户都意识不到有问题的艺术。等等不好意思,这是亚马逊化。优化是指根据你那些昂贵的菜鸟程序员写出来的垃圾代码⽣成“正确”代码的艺术。保守派和⾃由派,你属于哪派?软件⼯程有⾃⼰的政治轴⼼,—端是保守派,另—端是⾃由派。毕竟“保守的”这个形容词基本上和谨慎、厌恶风险就是同义词。⾦融上的保守主义常常(也是显⽽易见的)和年龄以及财富联系在⼀起。公司会随着时间逐渐变得保守起来,因为它们熬过过了各种法律诉讼、技术失败、公共危机、⾦融风暴等危机。连蚂蚁和蚱蜢的寓⾔故事都告诉我们寒冬将⾄,要储存⾷物。本质上,保守主义就是风险管理。同样⾃由派的观点常常和年轻、理想主义、天真⽆邪联系在⼀起。在企业⾥,创业公司往往是典型的⾃由派,⼀部分原因是他们本来就是为了(在⼀定程度上)改变世界⽽存在的(⽽⾃由主义原本就意味着变化),另⼀部分则是他们必须全⼒以赴完成投资⼈设定的⽬标,所以放弃⼀点软件安全也就变得合理(不得已)了。 me:保守派,尽量修复所有bug,回避错误,学不会新语法,通过编译器安全检查,数据必须遵循事先定义好的格式,公共接⼝必须严格建模,⽣产系统⾥绝不允许存在危险过有风险的后门,安全性有疑虑就不能上线,快⽐慢好,注重性能。⾃由派则相反。各⼤语⾔的分派:(作者⾃⼰使⽤语⾔的经验,仅供参考)难以⾔喻的⾃由:汇编语⾔极端⾃由:Perl、Ruby、PHP、脚本⾮常⾃由:JavaScript、VB、Lua ⾃由:python、Comm
on Lisp、Smalltalk/Sqeak 温和⾃由:C、Object-C、Schema 温和保守:C++、Java、C#、D、Go 保守:Clojure、Erlang、Pascal ⾮常保守:Scala、Ada、Ocaml、Eiffel 极端保守:Haskell、SML
(1)Facebook是极端⾃由的。他们主要⽤的是C++和php,他们的数据都放在memcached⾥:只有键值对,没有数据库结构。他们把数据导出来放到⼀个后台Hⅳe数据仓库⾥,然后⽤Hadoop来进⾏离线数据分析。每两个星期左右他们仍然会举办通宵⿊客马拉松,反正他们的程序员⼤多都是单⾝男青年(⾄少我上次去参观的时候还是如此),股票的估值也还很⾼(我上次查价格的时候好像已经没那么好了)。作为⼀家公司,Facebook是⾮常紧密的,具有很强的执⾏⼒,⼗分注重程序员在⽹站上发布新功能的单兵能⼒,没有什么官僚主义。这对⼀家规模这么⼤、⽤户那么多多的公司来讲是难能可贵的。保守派毫⽆疑问会厌恶蔑视他们。但是Facebook证明了不管具有什么世界观的程序员,只要联合起来,就能解决很多问题。(2)Amazon是⾃由的。(3)Google是保守的。开始是有点⾃由的,然后就变得越来越保守了。只有在刚刚开始的时候才是软件⾃由的,那时候的搜索引擎是⽤Python写的。随着公司不断壮⼤,他们很快就转向了软件保守主义,⽽这完全是由⼯程师⾃⼰主导的。他们写了很多宣⾔警告太多语⾔所带来的危险,⽽仅有的⼏门语⾔⾥,也⾥,也有严格的风格指南,限制使⽤那些端保守,险”或者“难以阅读”的语⾔特性。(4)微软是难以⾔喻的保守。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。