几周前,我在浏览GitHub时遇到了一个奇怪的存储库:该项目完全是用Nim编写的。在那之前,我没有遇到过他,这次我决定弄清楚那是哪种动物。
起初我以为我落后于时代,这是许多与我不同的人积极使用的通用编程语言之一。然后我决定研究它。
这是我的结论:
- 实际上,这种语言在狭窄的人群中很流行。
- 也许应该是这样。
因此,我将向您介绍一些有关Nim的经验,简要介绍其中的编程功能,并尝试将其与Python和C进行比较。展望未来,我注意到这种语言对我来说非常有前途。
在工作室编码!
例如,我决定在Nim中写一些比世界打招呼更复杂的东西:
似乎没有什么多余的,对吧?看起来是如此简单,即使您以前从未听说过Nim,也可以轻松找出它的作用。(程序将输出:“ num:5 i:5”)
因此,让我们从某个地方分析一下我们似乎熟悉的东西。
变量声明
这对JavaScript开发人员来说是非常痛苦的。虽然有些语言使用var,有些语言使用let,但是JS和Nim允许您在声明变量时同时使用这两种语言。但是,需要注意的是,它们在Nim中的工作方式不同于在JS中的工作方式。但是稍后会更多。
积木
为了表示Nim中的新块,我们使用冒号后接缩进线。一切都像在Python中一样。
关键词
循环和if语句看起来都像是一段Python代码。实际上,从第5行开始的所有内容都是Python代码(假设我们定义了echo函数)。
因此,可以,Nim中也可以使用许多Python关键字和运算符:not,is,and,or等等。
也就是说,到目前为止,我们没有在Nim中看到什么特别的东西:Python的最差版本(就
语法而言),考虑到需要使用let或var声明变量的事实。
我们可以在这里停下来,但是有一个很大的“但是”:Nim是一种静态类型的语言,其运行速度几乎与C语言一样快,
好了,现在再进行一次对话。让我们来看看。
性能测试
在深入探讨Nim的语法(尤其是到目前为止尚未看到的静态类型的部分)之前,让我们尝试评估其性能。为此,我编写了一个简单的实现来计算Nim,Python和C中的第n个斐波那契数。
为了公平起见,我基于Leetcode解决方案(选项1)对实现进行了标准化,并尝试在所有三种语言中尽可能严格地坚持下去。
您当然可以提醒我有关LRU Cache的信息。但是目前,我的任务是使用标准方法,而不是尝试优化计算。所以我选择了一个简单的实现。
以下是计算第40个斐波纳契数的结果:
是的,严格来说,不能将实验称为“干净”,但这与进行更认真测试的其他发烧友的结果相关[1] [2] [3]。
我为本文编写的所有代码都可以在GitHub上找到,包括有关如何运行此实验的说明。
那么,为什么Nim比Python快得多?
好吧,我要说有两个主要原因:
- Nim是一种编译语言,而Python是一种解释语言(更多内容请参见)。这意味着在运行Python程序时需要做更多的工作,因为必须先解释该程序,然后才能运行。这通常会使语言变慢。
- Nim是静态类型的。尽管在我之前显示的示例中没有类型声明,但稍后我们将看到它确实是静态类型的语言。对于动态类型的Python,解释器还有很多工作要做,以适当地定义和处理类型。它还会降低性能。
工作速度增加-编码速度降低
这是Python Docs关于解释语言的说法:
« / , , ».
例如,这很好地概括了Python和C之间的折衷。您可以在Python中做的任何事情都可以在C中做,但是C程序将运行许多倍。
但是您将花费更多的时间编写和调试C代码,因为它笨拙且可读性差。这就是为什么不再需要C且Python受欢迎的原因。换句话说,Python要简单得多(当然,是相比而言)。
因此,如果Python在光谱的一端,而C在光谱的另一端,则Nim试图在中间找到某个位置。它比Python快得多,但编程起来却不像C难。
让我们看一下计算斐波纳契数的实现。
从:
#include <stdio.h>
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n-1) + fibonacci(n-2);
}
int main(void) {
printf("%i", fibonacci(40));
}
蟒蛇:
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(40))
尼姆:
proc fibonacci(n: int): int =
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
echo(fibonacci(40))
尽管Nim在其过程(函数)语法中使用“ =”符号,但总的来说,编写代码比使用C语言要容易得多。
也许这确实是一个值得权衡的选择吗?比Python难写一点,但是它的运行速度快十倍。我可以忍受。
Nim语法
import strformat
# https://nim-lang.org/
type
Person = object
name: string
age: Natural #
let people = [
Person(name: "John", age: 45),
Person(name: "Kate", age: 30)
]
for person in people:
echo(fmt"{person.name} is {person.age} years old")
我只是指出关键功能。
变数
我们使用var,let或const声明变量。
var和const的工作方式与JavaScript中的工作方式相同,但是让我们有一个不同的故事。
JavaScript let在范围方面与var不同,Nim let表示一个变量,其值在初始化后不能更改。在我看来,它就像Swift。
但这不等于常量吗?- 你问。
没有。在Nim中,const和let之间的区别如下:
对于const,编译器必须能够在编译时确定该值,而对于let,则可以在运行时确定该值。
文档中的示例:
const input = readLine(stdin) # Error: constant expression expected
let input = readLine(stdin) #
另外,可以像这样声明和初始化变量:
var
a = 1
b = 2
c = 3
x, y = 10 # x y 10
功能
Nim中的函数称为过程:
proc procedureName(parameterName: parameterType):returnType =
return returnVar
鉴于该语言在许多方面与Python相似,因此当您初次看到它们时,这些过程似乎有些奇怪。
使用“ =”而不是“ {”或“:”显然会造成混淆。在同一行中编写过程,一切都会好一点:
proc hello(s: string) = echo s
您还可以获得函数的结果:
proc toString(x: int): string =
result =
if x < 0: “negative”
elif x > 0: “positive”
else: “zero”
感觉您仍然需要以某种方式返回结果,但是在这种情况下,结果不是变量-它是关键字。因此,从Nim的角度来看,上述代码段是正确的。
您还可以重载过程:
proc toString(x: int): string =
result =
if x < 0: "negative"
elif x > 0: "positive"
else: "zero"
proc toString(x: bool): string =
result =
if x: "yep"
else: "nope"
echo toString(true) # "yep"
echo toString(5) # "positive"
条件和周期
它与Python有很多关系。
# if true:
# while true:
# for num in nums:
例如,要遍历列表,可以使用countup(开始,完成)或countdown(开始,完成)来代替range()。您可以更轻松地完成它,并在开始时将其用于i..finish
用户输入和输出
let input = readLine(stdin)
echo input
与Python相比,readLine(stdin)等效于input(),echo等效于print。
echo可以带或不带括号。
我的目标是使您对Nim有了基本的了解,而不是重述其所有文档。因此,我结束了语法,然后继续讲其他语言功能。
额外功能
面向对象编程
Nim不是一种面向对象的语言,但确实为使用对象提供了最少的支持。当然,他远离Python类。
巨集
Nim支持宏和元编程,并且开发人员似乎对此非常重视。这是三个课程系列中其自身部分的主题。
小例子:
import macros macro myMacro(arg: static[int]): untyped =
echo arg
myMacro(1 + 2 * 3)
基本数据类型
string, char, bool, int, uint float.
您还可以使用以下类型:
int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64
另外,与Python不同,Nim中的字符串是可变类型。
评论
与Python不同,Nim使用“#”字符和“ [”和“]”组合来进行多行注释。
# a comment#[
a
multi
line
comment
]#
编译JavaScript
Nim可以将其代码转换为JavaScript。不知道是否有很多人来使用它。但是有一个用Nim编写的Snake浏览器游戏的例子。
迭代器
Nim迭代器更像Python生成器:
iterator countup(a, b: int): int =
var res = a
while res <= b:
yield res
inc(res)
区分大小写 和下划线Nim仅对第一个字符区分大小写。
也就是说,他区分HelloWorld和helloWorld,但不区分helloWorld,helloworld和hello_world。因此,例如,以下过程将正常工作:
proc my_func(s: string) =
echo myFunc("hello")
尼姆有多受欢迎?
Nim在GitHub上拥有近10,000个星星。这是一个明显的优点。不过,我尝试从其他来源估算该语言的普及程度,当然,它的普及程度还不高。
例如,在2020 Stack Overflow Survey中甚至没有提到Nim 。我在LinkedIn上找不到Nim开发人员的工作(即使在全球范围内也是如此),并且在Stack Overflow上搜索[nim-lang]标签仅返回了349个问题(对于Python来说,这大约为1,500,000,而对于Swift则为270,000)
。因此,可以假设大多数开发人员都没有使用过它,并且许多人从未听说过Nim语言,这是公平的。
取代Python?
老实说,我认为Nim是很酷的语言。为了撰写本文,我研究了所需的最低要求,但这足够了。尽管我还没有对它进行深入的研究,但我计划将来使用Nim。就个人而言,我是Python的忠实拥护者,但我也喜欢静态类型的语言。因此,对我而言,在某些情况下,性能的提高可以弥补轻微的语法冗余。
虽然基本语法与Python非常相似,但更为复杂。因此,大多数Python爱好者可能对它不感兴趣。
另外,不要忘记Go语言。我相信你们中的许多人在阅读时都已经想到了这一点,这是正确的。尽管Nim的语法更接近于Python的语法,但就性能而言,它与诸如``简化的C ++''之类的语言精确竞争。
我曾经测试过Go的性能。特别是对于斐波那契(40),它的工作速度与C一样快。
但仍然:Nim可以与Python竞争吗?我非常怀疑。我们看到了提高计算机性能和简化编程的趋势。而且,正如我指出的那样,即使Nim提供了良好的语法/性能折衷,我认为击败纯粹和通用的Python还不够。
我与一位Nim Core开发人员进行了交谈。他认为Nim更适合从C ++迁移的人员,而不是python专家。
Nim可以与Go竞争吗?可能(如果Google允许)。Nim语言与Go一样强大。而且,Nim对C / C ++功能(包括宏和重载)有更好的支持。
但是,下次还会有更多关于此的信息。
广告
Epic服务器是价格实惠的虚拟服务器,具有AMD处理器,CPU核心频率高达3.4 GHz。最大配置将使您充分利用-128个CPU内核,512 GB RAM,4000 GB NVMe 快点订购!