与C++、D、Java、C#、Go、Rust和Swift等之前的C竞争对手的比较在很多方面,我的整个编程生涯就像是漫长的等待替代C的等待。20年前,尽管我使用C++。随着时间的推移,我了解到C++是一个复杂的怪物,无论我读了多少书都无法驯服。我认为YossiKreinin和他的C++常见问题解答(https://yosefk.com/c++fqa/)很好地总结了我讨厌C++的所有方面。所以当谈到成为一名专业的C++程序员时,我总是会考虑其他选择。第一个有前途的替代品是D。D最初看起来很有前途,但仔细观察后,我认为D实际上只是一个根本上不好的想法的清理版本。C++的主要问题之一是它的接收器语言设计方法。在用C和Lua实现一个简单的游戏引擎的时候,我发现这两种语言的想法其实都比C++少。它让我重新爱上了C。尽管有其局限性,但C是一种相当简单的语言,提供了很多控制。Java和C#在很多方面只是试图重新实现C++。他们可能让事情变得更简单,但他们最终陷入了虚拟机和90年代面向对象编程的炒作中。并不是说Java或C#不好,很大程度上可能与支持臃肿的IDE和过度设计的语言的相关社区有关。C简洁性的回归从Google转向Go是对冗余C++、D、Java和C#的告别。Go将我们带回到我们开始的地方,回到C。如果你不冒险走C++的道路,Go会重新想象C可能是什么。我们得到的是一种简单的语言,它解决了我在使用C时经常遇到的许多问题。但是故事还没有结束。在Go之后,我们得到了Rust。最初,我认为Rust实际上一直是D应该的样子。真正重新思考C++应该是什么。Rust保持低级控制、高级抽象机制和手动内存管理,但增加了无与伦比的类型安全性。一切看起来都好得令人难以置信。坦率地说,我是这么认为的。我记得能够在两天内用Go编写一些不错的程序。朱莉娅,我目前最喜欢的也有点相似。另一方面,学习Rust就像学习Haskell。在做任何有用的事情之前,只需要了解很多概念和理论。如果C++教会了我任何东西,那就是重视简单性,而Rust没有。后来从网上很多Rust用户的评论中了解到,Rust重复了C++的一个主要缺点。它的编译时间真的很慢。我认为没有什么比等待C++编译更能破坏我编程的乐趣了。听起来Rust更糟。那是一个交易破坏者。Swift-我想爱的语言我已经成为Apple的铁杆粉丝20年了。在iPhone出现之前,我很喜欢CocoaGUI库和Objective-C编程,突然之间每个人和他们的宠物都在使用Objective-C编程。是的,Objective-C有点笨重,但它的简单性也有一定的美感。与C++不同,它是对C语言的一个相当简单的补充。有了经验,您实际上可以非常快速地教初级开发人员Objective-C。所以Swift的发布让我觉得我已经达到了编程的必杀技。最后,一种与Objective-C很好集成的非常现代的语言,因此我们仍然可以使用像Cocoa这样的伟大的Apple库。Swift从Rust中借鉴了很多想法,在很多方面,我认为我们终于为普通人提供了Rust。Swift可以在相当短的时间内学会。但我对Swift的体验是喜忧参半的。即使在今天,我仍然无法正确使用语言,因为它似乎解决了很多问题。我将一个iPhone应用程序从Objective-C移植到Swift。我有过的最好的经历之一是Swift发现了一大堆错误,仅仅是因为严格的类型系统捕获了在Objective-C中不可见的问题,在编译时至少是关于类型的,这很好已知。我会说与C++、C#和Java相比,Swift是更好的语言。Swift用C++解决了我几乎所有的具体问题。但每次使用Go时,我都意识到编写Go程序比Swift有趣得多。但是Go的错误处理有点糟糕,它用空指针重复了百万美元的错误。Swift避免了这两个问题。当我在上次使用Julia很长时间后回到Swift时,我看到Swift的一些问题变得更加清晰:Swift语法不适合函数式编程Smalltalk-inspiredsyntaxinheritedfromObjective-Cinobject-orientedprogrammingworksfinein,但是对于函数式编程来说很糟糕。作为一等公民使用函数时,您无需费心确保参数名称正确。面向对象编程和函数式编程之间的休战。Swift试图为两个不同的主人服务,并为此受苦。在进行非常务实风格的编程时,您希望您的函数主要是自由函数。这些更容易在功能设置中传递和使用。但Swift最终主要面向OOP人群,将函数放在方法中。一旦你完成了大量的函数式编程,这会变得很麻烦。Zig在编程世界中处于什么位置?所以Swift从未真正成为我最终的通用编程语言。如果我想在更高的抽象层次上编程,获得高性能并完成工作,我会选择Julia。但这仍然为C之类的替代方案留下了未填充的空间。Julia无法真正取代C。它会占用内存,不会生成小的二进制文件,并且不适合使库可供其他语言使用。您不想用它来创建操作系统内核或对微控制器进行编程。Go和Rust都非常接近于取代C。Go远离了C的简单性和感觉。但它并不能完全取代使用垃圾收集的C。与Java相比,Go对内存使用的更多控制仍然毫无价值,因为您可以获得指针并实际创建自己的辅助分配器。Rust减少了手动内存分配,但没能复制C的简单和感觉。也许这两种语言之间有什么可以填补的?有。我认为这是齐格。Zig比Go更复杂,但比Rust更容易学习和使用。但是,这样的Zig摘要并不能使语言公正。Zig带来了许多新想法,这是有道理的,并使Zig编码体验非常独特。但在我们深入研究之前,让我们先了解一下基础知识。掌握正确的基础如果我们要学习另一种类似C的语言,我们将无法重复C++最糟糕的部分,例如糟糕的编译时间。Zig是如何解决这些问题的?我遇到了V编程语言的创建者AlexanderMedvednikov的测试。这是一个编译具有400K函数的文件的测试:C5.2秒gcc测试C++1分25秒g++test.cppZig10.1秒Zigbuild-exetest.zigNim45秒nimctest.nimRust30Rust在之后停止Swift30分钟的rustctest.rs在30分钟的swiftc测试后停止D在dmd测试6分钟后出现段错误。dV0.6秒v测试vRust,Swift和D均失败。Medvednikov用更少的行进一步测试了这些语言,Rust再次表现出最差的预期。从名单中可以看出,Zig是最突出的演员。虽然很难不注意到V语言在几分之一秒内就完成了这一切。这提醒我更详细地探索V。快速扫描显示它可以手动分配内存、泛型和可选(必须明确允许空指针)。Zig内存分配如果没有手动内存管理,您将无法使用C。任何进行C风格编程的人都期望这一点。如果我不需要,那么我可以对Julia进行编程。Zig没有提供Rust提供的那种最高安全性,但它确实获得了一个更容易让初学者掌握和使用的模型。任何需要在Zig中分配内存的东西都需要一个分配器作为参数。所以Zig非常明确何时需要内存管理。这是我编写的一个简单函数,它采用32位无符号整数n并将其拆分为十进制数字:fndecimals(alloc:*Allocator,n:u32)!Array(u32){varx=n;vardigits=Array(u32)。init(alloc);errdeferdigits.deinit();while(x>=10){trydigits.append(x%10);xx=x/10;}trydigits.append(x);returndigits;}请注意数组用于保存各个小数位的数字必须使用分配器进行分配,分配器是decimal函数的参数。这就是Zig真正闪耀的地方。确保您不会忘记分配内存在C中很难。而且很容易在错误的位置结束内存。Zig复制了Go的延迟概念。但除了推迟它还有errdefer。如果您不了解Go,延迟本质上是一种推迟执行一行或代码块直到函数退出的方法。为什么这样好?因为它允许您确保某些代码运行,而不管在退出函数之前使用的任何复杂的if-else语句。errdeferdigits.deinit();上面这行与普通的Godefer不同,它只有在返回错误代码时才会执行。所以如果一切正常,它永远不会运行。在呼叫站点,我们将使用常规延迟来确保我们不会忘记释放分配给该号码的内存。constdigits=trydecimals(allocator,4123);deferdigits.deinit();for(digits.items)|digit|{tryprint("{},",.{digit});}根据我用Zig玩游戏的有限经验,我会说这是一个很好的系统。allocators和defer的组合使得你想要分配和释放内存的位置非常清楚,同时也很容易正确地做到这一点。C与许多类C语言兼容的问题是它们不能很好地与C一起玩。这意味着从该语言调用C函数应该很容易,调用一个函数应该很容易从C到那种语言。此外,您编写程序的一般方式应该与C完全兼容,因此您不必创建大型C抽象级别。例如。C++对C不是很友好,因为如果不进行大量包装,就无法在C中使用典型的C++库。但是Zig非常C,因为它不会暴露C没有得到的奇怪东西。结构中没有vtable(C++中的虚函数表)。没有C知道如何调用的构造函数或析构函数。无一例外,C也抓不住。从Zig使用C很容易。事实上,Zig的创建者会声称Zig比C本身更擅长使用C库。constc=@cImport({@cDefine("_NO_CRT_STDIO_INLINE","1");@cInclude("stdio.h");});pubfnmain()void{_=c.printf("hello\n");}如您所见,Zig可以毫无问题地解析C头文件并包含来自C的类型和函数。实际上Zig是一个完整的C编译器。如果需要,您可以使用Zig来编译C程序。此外,将Zig函数暴露给C也很容易。这是一个Zig函数,它接受一个32位整数并返回一个32位整数。exportfnadd(a:i32,b:i32)i32{returna+b;}通过将export放在它前面,使我们与程序链接的C代码可以访问它。其实我们的main函数是在C代码段定义的,使用了Zig中定义的函数。#include
