网易首页 > 网易号 > 正文 申请入驻

从软件工程的角度比较 Swift、Go 和 Julia,我有了这些发现!

0
分享至

作者 | Erik Engheim

译者 | 弯月

出品 | CSDN(ID:CSDNnews)

从已有代码的扩展和重用方面考虑,这几种语言的类扩展、duck type(鸭子类型)和多分发孰优孰劣?

面向对象编程(OOP)是组织大型程序的方式之一,但并不是唯一的方式。本文将从代码重用的角度比较Swift、Go和Julia。Swift采用了OOP方式,还支持接口和类扩展。Go尝试从新的角度考虑代码重用问题,在静态类型语言中引入了duck类型。而Julia拒绝使用OOP范式,而是发明了自己的范式:多分发。

下面,我们就来看看每种方式的优缺点。

Swift协议和类扩展

如果你想要传统的面向对象编程,那么很少有主流语言能打败Swift。没错,我的意思是,虽然Java和C#等语言与Swift差不多,但都不如Swift。那么Python如何?Python是一门优秀的面向对象语言。但这种比较不太容易,因为Python是动态类型。而Swift是静态类型,因此与Java或C#比较更容易。

但究竟是什么让Swift 成为了一个强力的面向对象语言?答案是类扩展和协议。下面是最近的一段代码中的例子。我需要在有序数组中支持二分查找。这样就能在O(log N)的时间内找到数组中的某个元素,例如8,同时不需要检查每个元素。下面是Swift代码:


let xs = [2, 4, 8, 10]let i = xs.binarySearch { x in x < 8 }

但Swift中的数组并不支持binarySearch。一些习惯了传统OOP语言的人可能会选择创建数组的子类。但是这会导致混乱的继承结构。继承应当用于表示新概念,而不是用来添加新功能。

但是在Swift中,你可以扩展接口(Swift称之为协议)来添加新方法。Swift的Array类实现了RandomAccessCollection接口,它属于标准库。但我们可以向这个接口添加任何新方法。我们甚至可以提供默认实现:


extension RandomAccessCollection { funcbinarySearch(predicate: (Iterator.Element) -> Bool) -> Index { var low =startIndex var high =endIndex while low !=high { let mid =index(low, offsetBy: distance( from: low, to: high)/2) ifpredicate(self[mid]) { low =index(after: mid) } else { high= mid } } return low }}

这意味着Swift中任何实现了RandomAccessCollection接口的集合类型都可以使用binarySearch方法。

你几乎可以扩展任何东西,而不仅仅是接口。你也可以扩展类、枚举和结构。NSRange是一个结构(值语义的类),表示范围。它可以表示诸如文本视图中选中的文本,或字体和颜色均相同的一段字符。我编写了自己的WrittenDoc类,用于容纳可以打标签的文本。我希望创建一个范围,表示从一个标签到下一个标签。因此只需要扩展NSRange结构,给它一个额外的初始化器:


extension NSRange { init(doc:WrittenDoc, tag: Tag) { self.init(doc.charIndex(ofTag: tag)..count) }}

因此,代码可以这样写:


let nextTag : Tag = tags[i+1]let range : NSRange = NSRange(doc: self.writtenDoc,tag: nextTag)

这个特性可以实现许多想都不敢想的事情。例如,在Swift中,一个字符串可以自己在屏幕上描绘自己。听起来这不像是正确的设计,因为这样需要把GUI和图形代码放到核心库中。但是,Swift并不是这样做的。如果只导入Foundation库,描绘功能是无法使用的。

但是,如果还导入了Cocoa库,就会包含一个针对String的类扩展,允许字符串描绘自己。这样,扩展就可以应用到不同的库中。图形相关的代码可以专门放到图形库中,但依然可以扩展基本类型。

这有什么用呢?它能解决访问者模式之类貌似有点别扭的模式。

Go中的duck类型

当然,面向对象编程并不是解决问题的唯一方法。Go使用了面向对象编程的元素,但尽可能保持简单。

在Go中,你不需要明确标示出对象实现了接口;只要它包含接口中列出的所有方法,就自动实现了该接口。因此,只要拥有类似Write方法的类都实现了Write接口。


type Writer interface {Write(p[]byte) (n int, err error)}

因此在Go中,你可以从已有的库中发明新接口,它就会自动实现,而不需要专门设计接口。这一点非常像Swift。

但与Swift不同,你不能扩展已有类型。相反,Go的方法是使用自由函数为简单接口添加功能。举个例子:


func main() {filename :="rocket-engine.txt"file, err :=os.Create(filename)if err != nil {fmt.Fprintf(os.Stderr, "Could not create %s because: %v\n",filename, err)os.Exit(1)}deferfile.Close()engine :="RD-180"var thrustfloat64 = 3830fmt.Fprintf(file,"%s has thrust %0.1f\n", engine, thrust)}

这里可以看到,fmt.Fprintf函数用来向stderr和打开的文件写入格式化后的文本。fmt.Fprintf关心的只是第一个参数有没有遵循Write接口。你还可以在此基础上构建更多功能,从而为所有实现了Write接口的类型创建更复杂的功能。

这种方法的局限性是,你无法为不同的类型创建不同版本的Fprintf。在Swift中这样做是可能的。在Swift中,只需添加一个支持Fprintf的接口扩展,就能提供一个默认的实现,就像Go中的自由函数一样,但是可以为特定的类型提供一个特殊的Fprintf。但Go没有办法解决这个问题,除非使用并不太优雅的类型切换语句。

Julia中的多分发

虽然Swift中的面向协议的编程和扩展非常强大,但我仍然要说,Julia的多分发在组织和重用代码方面有更强大的范式。

下面来解释一下它的工作原理。我们假设Go和Swift都有类似于Julia的类型和接口,这样方便我们看到其中的区别。假设Swift和Go都有一个show函数或方法、IO接口和Any接口。

在Julia中对表达式求值,即可获得一个对象,该对象会在REPL(交互式命令行环境)中显示如下:


julia> xs = [3, 4, 8]3-element Vector{Int64}:348

在Julia的提示符下,我创建了一个拥有3个元素的数组,存储在变量xs中。按回车键之后,Julia输出了该数组的描述。在Julia中,这是通过调用show方法完成的。当命令行需要显示一个对象时,就会调用其show方法。上例中调用方式大致如下:


show(output, xs)

它有两个参数。output表示控制台,xs是要显示的对象。Julia提供的默认实现大致如下:


function show(io::IO, obj::Any)# implementationcode goes hereend

该实现使用内省来确定类型拥有的字段并输出。因此,如果在Julia中创建自定义类型并初始化,就能得到一个合理的默认显示结果,如下面的构造函数调用:


julia> struct Pointx::Inty::Intend
julia> p = Point(3, 4)Point(3, 4)

但是,我可以通过重载show方法来改变Julia中的显示:


import Base: show
function show(io::IO, p::Point)print(io,"<", p.x, ", ", p.y, ">")end

现在,在REPL中显示p,就会得到不同结果:


julia> p<3, 4>

到这里一切都还好。Swift也可以做到这一切。假设它也支持Any接口,那么可以定义show方法如下:


extension Any {func show(io: IO){//implementation code goes here}}

然后Point类可以这样写:


extension Point {func show(io: IO){io.print("<", self.x, ", ", self.y,">")}}

但接下来Swift就力不从心了。假设我们需要通过UDP套接字发送一个Point的文本表示,需要发送一个特殊的表示。在Julia中可以这样写:


function show(io::UDPSocket, p::Point)print(io,"(", p.x, ", ", p.y, ")")end

这样就能通过UDP套接字发送(3, 4)而不是<3,4>。这个例子的确不太恰当,但可以演示为何多分发要更强大。

另一个更明显的例子就是处理不同几何形状的交点。在游戏编程中经常会用到这一功能,来判断不同几何体之间的碰撞情况。几何体可能是正方形、圆形或多边形。Julia可以定义一个方法来处理所有情况:


collide(a::Circle, b::Triangle)collide(a::Square, b::Circle)collide(a::Polygon, b::Square)

实际上这正是Julia中数值提升系统的工作原理。它会找到多个数值类型中的最小公倍数。

多分发的缺点

多分发看起来很不错,但它有什么缺点呢?OOP的优点是方法永远属于对象。只要有对象,就能查找其方法。但在Julia中,方法属于函数,而不是对象(准确地说是类型)。

如果很熟悉OOP的话,“方法”这个术语可能会让你感到迷惑。看一下collide的例子,它演示了collide函数的三个不同的方法。方法是函数的具体实现。一个函数可以有多个实现,每个实现都可以有不同的参数个数和类型。

因此,如果有一个Circle,我无法得知它有collide方法,因为方法属于所有的参数。

这也意味着Julia中很难获知一个对象是什么。Julia并不像OOP语言那样,对每个对象及其所有方法有集中的定义。但是可以认为,Julia的思想更函数式一些。你不需要关心对象,只需要关心函数及函数的行为。OOP关注的是名词,而Julia关注的是动词。

https://erik-engheim.scribe.rip/software-engineering-in-swift-go-and-julia-compared-5937bcb63143

《新程序员003》正式上市,50余位技术专家共同创作,云原生和数字化的开发者们的一本技术精选图书。内容既有发展趋势及方法论结构,华为、阿里、字节跳动、网易、快手、微软、亚马逊、英特尔、西门子、施耐德等30多家知名公司云原生和数字化一手实战经验!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
新射雕英雄传:定档6月17日,五绝演员官宣,王重阳气质绝了!

新射雕英雄传:定档6月17日,五绝演员官宣,王重阳气质绝了!

综艺拼盘汇
2024-06-14 17:29:21
张海迪曾患十几种癌病,被判定只能活27年,为何活到现在快70岁?

张海迪曾患十几种癌病,被判定只能活27年,为何活到现在快70岁?

胥言
2024-03-11 23:22:23
儿子高考前去世,母亲一同火化了儿子的手机,几日后竟意外接通!

儿子高考前去世,母亲一同火化了儿子的手机,几日后竟意外接通!

华人星光
2024-06-15 16:19:40
A股:股市或将迎来暴风雨

A股:股市或将迎来暴风雨

生活中的栗子
2024-06-16 12:34:28
赵蕊蕊探班中国女排,被李盈莹喊阿姨,袁心玥应该取经

赵蕊蕊探班中国女排,被李盈莹喊阿姨,袁心玥应该取经

跑者排球视角
2024-06-15 18:56:37
2024年养老金调整前,人社部发文称要完善养老金调整机制,咋回事

2024年养老金调整前,人社部发文称要完善养老金调整机制,咋回事

小强财艺
2024-06-16 21:15:59
如果柏林墙没倒塌,你可能永远不知道亲友曾出卖你

如果柏林墙没倒塌,你可能永远不知道亲友曾出卖你

叶克飞
2024-06-14 13:49:26
当女人羞羞时,“咪咪”会发生什么变化?全看男人怎么操作

当女人羞羞时,“咪咪”会发生什么变化?全看男人怎么操作

水白头
2024-06-16 00:30:02
毛主席的命令:除大将外,从上将到少校,明年和我一起横渡长江!

毛主席的命令:除大将外,从上将到少校,明年和我一起横渡长江!

陈冠任
2024-06-16 09:02:20
随着许家印的没落,其女儿的生活也被曝光,奢侈程度令人咋舌

随着许家印的没落,其女儿的生活也被曝光,奢侈程度令人咋舌

天闻地知
2024-06-14 14:07:23
江苏卫视又出“王炸”了!36集谍战剧即将开播,实力派戏骨云集

江苏卫视又出“王炸”了!36集谍战剧即将开播,实力派戏骨云集

娱记掌门
2024-06-16 22:21:20
F-16登场,留给侵略者耀武扬威的时间不多喽

F-16登场,留给侵略者耀武扬威的时间不多喽

临墨有余
2024-06-13 09:06:39
林彪取代彭老总位置后,却一再和主席“顶牛”:大不了和彭总一样

林彪取代彭老总位置后,却一再和主席“顶牛”:大不了和彭总一样

燕小姐说历史
2024-06-16 08:48:13
具俊晔尴尬了!粉丝见面会只有18人,无助的说:让熙媛失望了!

具俊晔尴尬了!粉丝见面会只有18人,无助的说:让熙媛失望了!

田径龙超明
2024-06-16 21:34:43
21比4横扫!羽坛头号美女击败中国名将,网友:美貌和实力并存

21比4横扫!羽坛头号美女击败中国名将,网友:美貌和实力并存

体坛知识分子
2024-06-16 06:25:02
苹果首次展示卫星短信功能 仅限iPhone 14及以上机型

苹果首次展示卫星短信功能 仅限iPhone 14及以上机型

手机中国
2024-06-14 06:55:20
外媒:俄特种部队出手,人质获救

外媒:俄特种部队出手,人质获救

参考消息
2024-06-16 19:53:06
英国首相苏纳克和他的鞋,英国民众盯着他的脚不放了

英国首相苏纳克和他的鞋,英国民众盯着他的脚不放了

好笑娱乐君每一天
2024-06-16 08:51:39
17岁广州队门将吴梓桐:大家都很拼,可惜最终没能拿下三分

17岁广州队门将吴梓桐:大家都很拼,可惜最终没能拿下三分

懂球帝
2024-06-16 22:21:10
陈兴汉-南京栖霞建设股份有限公司原总经理

陈兴汉-南京栖霞建设股份有限公司原总经理

户外钓鱼哥阿旱
2024-06-16 17:10:57
2024-06-16 23:46:44
CSDN
CSDN
成就一亿技术人
24726文章数 241820关注度
往期回顾 全部

科技要闻

iPhone 16会杀死大模型APP吗?

头条要闻

欧洲猪肉业界:中国若限制进口将是梦魇

头条要闻

欧洲猪肉业界:中国若限制进口将是梦魇

体育要闻

没人永远年轻 但青春如此无敌还是离谱了些

娱乐要闻

上影节红毯:倪妮好松弛,娜扎吸睛

财经要闻

打断妻子多根肋骨 上市公司创始人被公诉

汽车要闻

售17.68万-21.68万元 极狐阿尔法S5正式上市

态度原创

时尚
家居
教育
游戏
军事航空

伊姐周日热推:电影《沙漏》;动漫《眷思量2》......

家居要闻

空谷来音 朴素留白的侘寂之美

教育要闻

有一类中考必考,分值不低,形式多样的物理题!你能满分吗?

Xbox《发条革命》发售日泄露?开发商发表情包调侃

军事要闻

以军宣布在加沙南部实行"战术暂停"

无障碍浏览 进入关怀版