认识Nim:一种具有类Python语法和C效率的语言几周前在GitHub上浏览时,我遇到了一个引起我注意的回购协议。它托管一个完全用Nim编写的项目。尼姆到底是什么东西?我想。我立刻得出结论,这是很多人使用的众多编程语言中的一种,而我只是一个不懂它的笨蛋。但我没有把它搁置一旁,而是决定:让我们对此有所了解。然后我有两个主要的认识:不,很多人不使用这种语言。但也许它应该。所以这里简要介绍一下我使用Nim的经历,一个快速编程教程,以及为什么这种语言对我来说看起来很有前途。给我看代码!这是我在Nim中编写的一个无用程序:它看起来很干净。它也非常简单,即使您以前可能从未听说过Nim,您也不难理解它的作用。(提示:它打印出数字:5i:5。)所以让我们分解一下这里看起来很熟悉的东西:JavaScript开发人员非常熟悉变量声明。虽然有些语言使用var而其他语言使用let,但JS和Nim都允许使用其中任何一种进行声明。需要注意的是,这两种语言的含义并不相同。但稍后会详细介绍。块语法为了在Nim中标记一个新块,我们使用一个冒号后跟一个缩进行。那就是蟒蛇。关键字、两个循环和if语句看起来都像是从Python中提取出来的。事实上,从第5行开始的所有内容实际上都是有效的Python(假设我们定义了echo函数)。所以是的,Python中的许多关键字和运算符在Nim中也有效,例如not、is和or等??。到目前为止,Nim并没有什么特别之处。由于我们需要使用let或var,它看起来像是一个较差的Python版本(从语法上讲)。但是如果我告诉你一些事情呢:Nim是一种静态类型的语言,运行速度几乎与C一样快。哦,现在我们正在谈论。友好匹配在深入研究Nim的语法之前(尤其是静态类型部分,我们还没有看到),让我们尝试支持我们关于其速度的声明。为此,我编写了一个程序来天真地(即没有动态规划)计算Nim、Python和C中的第n个斐波那契数。为了公平起见,我根据针对此问题的建议Leetcode解决方案(方法1)标准化了实现,并确保尽可能多地坚持三种语言。为了计算执行时间,我使用了Bashshell中时间输出的“真”值。这是计算第40个斐波那契数的结果:是的,这发生了。现在,这非常有限,远非科学实验,但它与其他人通过更严格的基准[1][2][3]发现的结果一致。但是,我将在本文中运行的所有代码都可以在GitHub上找到,包括有关如何进行此实验的说明。那么,为什么Nim比Python快这么多呢?好吧,我想说有两个主要原因。大大简化了,它们是:Nim是在解释Python时编译的(不同意?单击链接)。这意味着在运行Python程序时,比仅仅运行程序要完成更多的工作,因为它需要在真正执行之前进行解释。这通常会使语言变慢很多。Nim是静态类型的。虽然我之前展示的示例没有单一类型声明或注释,但我们稍后会看到它确实是一种静态类型语言。对于动态类型的Python,解释器需要做更多的工作来适当地确定和处理类型,这会减慢执行速度。运行得更快,写得更慢这是Python文档对解释语言的评价:“虽然解释语言的程序通常运行速度较慢,但??它们的开发/调试周期通常比编译语言更短。”例如,它很好地总结了Python和C之间的权衡。您可以在Python中完成的任何事情,您也可以在C中完成,并且您的程序将运行得更快几个数量级。但是,您将花费更多时间编写和调试C代码,并且代码会更长且可读性更差。这就是为什么C不再流行,Python如此。总之:Python“简单”(当然是相对而言)。因此,如果Python处于光谱的一端而C处于另一端,那么Nim正试图处于中间位置:有点快速和简单?像那样的东西。但让Nim脱颖而出的是,乍一看,它似乎已将权衡最小化。换句话说,它比Python快得多,但编程不如C难(或者感觉像经过简短检查)。为了说明这一点,让我们看一下斐波那契实验的代码。这是C代码:#includeintfibonacci(intn){if(n<=1){returnn;}returnfibonacci(n-1)+fibonacci(n-2);}intmain(void){printf("%i",fibonacci(40));}Python:defbonacci(n):ifn<=1:returnn返回fibonacci(n-1)+fibonacci(n-2)print(fibonacci(40))和Nim:procfibonacci(n:int):int=ifn<=1:returnnreturnfibonacci(n-1)+fibonacci(n-2)echo(fibonacci(40))尽管Nim有奇怪的proc东西,亲爱的上帝,使用=来声明函数(或程序,调用它们),但它仍然比C更干净。所以也许这是一个值得的权衡?比Python更难写,但速度快几十倍——我可以接受。Nim语法这里简单介绍一下Nim语法的一些要点::45),Person(name:"Kate",age:30)]forpersoninpeople:#Type-safestringinterpolation,#evaluatedatcompiletime.echo(fmt"{person.name}is{person.age}yearsold")变量变量使用var,let或const声明。var和const基本上就像JavaScript一样工作,但让我们有一个不同的故事。虽然JavaScript中的let与var在作用域上有所不同,但Nim中的let表示一个变量,其值在初始化后不能更改。有人告诉我这显然与Swift相似。但这不是一个常数吗?好吧,在Nim中,区别如下:使用const时,编译器必须能够在编译时确定值,而使用let时,它可以在运行时确定。文档提供了以下示例:constinput=readLine(stdin)#Error:constantexpressionexpectedletinput=readLine(stdin)#works您也可以这样声明变量:vara=1b=2c=3x,y=10#Bothx,yarea分配给10个函数Nim中的函数称为过程,它们的声明是这样完成的:第一眼看到他们很奇怪。使用=而不是{或:特别奇怪。但是,它在单行代码中看起来好一点:prochello(s:string)=echos您也可以从函数返回:proctoString(x:int):string=result=ifx<0:"negative"elifx>0:"positive"else:"zero"感觉还是应该返回结果,但是结果不是变量,而是关键字。上面的代码片段是完全有效的Nim。您还可以重载该过程:proctoString(x:int):string=result=ifx<0:"negative"elifx>0:"positive"else:"zero"proctoString(x:bool):string=result=ifx:"yep"else:"nope"echotoString(true)#Callsthesecondversion,prints"yep"echotoString(5)#Callsthefirstversion,prints"positive"控制流很像Python。#iftrue:#whiletrue:#fornuminnums:要遍历范围,请使用countup(start,finish)或countdown(start,finish)而不是范围。或者,您可以简化整个过程并使用:foriinstart..finish。打印并获取用户输入letinput=readLine(stdin)echoinput与Python相比,readLine(stdin)相当于input(),echo相当于print。echo可以带括号也可以不带括号。我的目标是让您体验Nim,而不是通读它的完整手册。所以我想我会在这里停止使用简单的语法,而只是浏览一些其他功能。附加特性面向对象编程Nim不是面向对象的,但对对象的支持很少。但是,它们不像Python类那样整洁。宏Nim支持宏和元编程,事实上,它似乎非常重视它。由三部分组成的教程系列的整个部分专门介绍它。下面是一个简单的例子:importmacrosmacromyMacro(arg:static[int]):untyped=echoargmyMacro(1+2*3)基本类型Nim中的基本类型有:String、Char、Boolean、Integer、Integer和Float。这些也是有效的:int8int16int32int64uint8uint16uint32uint64float32float64此外,与Python不同,字符串在Nim中是可变的。注释你可能已经在上面的Python语法中看到了我的注释,但与Python不同的是,多行注释还使用散列符号(后跟[或]):#acomment#[amultilinecomment]#JavaScriptCompilation来自Nim网站:“Nim包含第一个-classJavaScript后端,因此您可以轻松地同时针对客户端和服务器。”虽然我不确定有多少人会实际使用它,但它非常酷。但是,如果你想玩用Nim编写的BrowserSnake,你可以这样做。但是这次我没有建造它。迭代器除了定义一个proc,还可以定义一个迭代器。然而,Nim迭代器实际上更像是Python生成器。下面是一个例子:iteratorcountup(a,b:int):int=varres=awhileres<=b:yieldresinc(res)不区分大小写和下划线Nim不区分大小写和下划线(第一个字符除外)。所以,HelloWorld和helloWorld是不同的,但是helloWorld、helloworld和hello_world都是一样的,所以这行得通:procmy_func(s:string)=echosmyFunc("hello")听说Nim或使用Nim!那样的话,嘿,我真为你高兴。但是,我确实尝试获取有关该语言流行度的一些信息,而且肯定没有那么高。例如,在2020年StackOverflow调查中甚至没有提到Nim。我在LinkedIn上找不到Nim开发人员的职位(位置设置为Worldwide),而且该语言的StackOverflow标签上只有349个问题。(与Python的1,500,000种或更新的语言如Swift的270,000种相比。)所以可以肯定地说,大多数开发人员都没有使用过它,许多人甚至从未听说过Nim这个名字。一个真正的Python替代品?老实说,我认为Nim会很酷。在撰写本文时,我已经做了最低限度的工作,所以还没有深入了解它,但我可以预见自己将来会使用它。然而,虽然基本语法与Python非常相似,但它变得非常复杂和快速,我相信这会吸引许多Python用户/开发人员。就个人而言,我是Python的忠实粉丝,也是静态类型语言的忠实粉丝,所以对我来说,在某些情况下,性能的提升将足以弥补增加的冗长。然后,写这篇文章,我意识到:围棋呢?我相信你们中的许多人在阅读时都在思考这个问题,这是有道理的。虽然Nim的语法可能更接近Python,但它确实在高性能但比C++更强大的语言中存在一些激烈的竞争,由Go语言主导。有趣的事实:我还偷偷用Go进行了速度测试。尤其是fibonacci(40),和C一样快。那么,Nim能和Python抗衡吗?我非常怀疑。正如我所指出的,我们看到了计算机变得越来越快和编程越来越容易的趋势,以至于我认为采用简洁和通用的Python是不够的,尽管Nim提供了一个很好的权衡。编辑:我与NimCoreDevs的发言人交谈过,他告诉我他认为Nim对于从C++过渡的人来说比Python更好。但是,它能与Go竞争吗?也许(如果谷歌不支持Go)。语法友好,语言强大,比Go提供的C/C++特性支持更好,比如宏和重载。也许那是我的下一篇文章。谢谢阅读!