ZIG 0.7.0发布

2020-11-09 05:17:46

没有隐藏的控制流,没有隐藏的内存分配,没有预处理器,也没有宏。如果Zig代码看起来不像是跳过去调用函数,那么它就不是。这意味着您可以确保下面的代码只调用foo(),然后调用bar(),这是可以保证的,而不需要知道任何东西的类型:

D有@Property函数,这些方法看起来像是通过字段访问来调用的,所以在上面的例子中,C.D可能会调用一个函数。

C++、D和Rust具有运算符重载,因此+运算符可以调用函数。

C++、D和Go都有抛出/捕捉异常,因此foo()可能会抛出异常,并阻止调用bar()。

Zig通过使用语言关键字和函数调用来独占地管理所有控制流,从而提高了代码的可维护性和可读性。

Zig有四种构建模式,它们都可以混合和匹配,一直到作用域的粒度。

下面是Integer溢出在编译时的样子,与构建模式无关:

编译时测试";整数溢出";{const x:u8=255;const y=x+1;}

$zig test test.zig./docgen_tmp/test.zig:3:17:错误:操作导致溢出const y=x+1;^。

$zig test test.zig1/1test";运行时整数溢出";...测试";整数溢出/home/andy/dev/www.ziglang.org/docgen_tmp/test.zig:3:7:0x204e00;运行时整数溢出";(测试)x+=1;std.Special.main(测试)}ELSE TEST_fn.func();^/home/andy/Downloads/zig/lib/std/special/test_runner.zig:48:28:0x2308d5;Std.start.posxCallMainAndExit(测试)中的^/home/andy/Downloads/zig/lib/std/start.zig:252:37:0x205c4d Const Result=root.main()Catch|err|{^/home/andy/Downloads/zig/lib/std/start.zig:123:5:0x20598f in std.star._start(TEST)@Call(.{.Modify=.Never_Inline},PoxCallMainAndExit,.{});^测试失败。使用以下命令重现failure:/home/andy/dev/www.ziglang.org/docgen_tmp/test。

使用Zig,人们可以依赖于启用安全的构建模式,并有选择地在性能瓶颈处禁用安全性。例如,可以这样修改前面的示例:

测试";实际未定义的行为";{@setRune meSafety(False);var x:u8=255;x+=1;//XXX未定义的行为!}。

Zig使用未定义的行为作为一种锋利的工具,既可以预防漏洞,又可以提高性能。

对于本机目标,由于交叉编译是一流的用例,因此启用了高级CPU特性(-march=ative)。

精心挑选的未定义行为。例如,在Zig中,有符号整数和无符号整数在溢出时都有未定义的行为,而在C中只有有符号整数。这有助于优化C语言中没有的优化。

ZIG直接公开了SIMD向量类型,使得编写可移植的向量化代码变得容易。

请注意,Zig不是一种完全安全的语言。对于那些对关注Zig的安全故事感兴趣的人,请订阅以下几期:

Zig标准库与libc集成,但不依赖于libc。以下是《Hello World》:

当使用--Release-Small、调试符号剥离、单线程模式进行编译时,这将为x86_64-Linux目标生成9.8 KiB的静态可执行文件:

$zig build-exe hello.zig--发布-小--条带--单线程$wc-c hello9944 hello$ldd Hello不是动态可执行文件。

$zig build-exe hello.zig--版本-小--条带--单线程目标x86_64-windows$wc-c hello.exe4096 hello.exe$file hello.exehello.exe:PE32+可执行文件(控制台)x86-64,适用于MS Windows。

顶级声明(如全局变量)是独立于顺序的,并且分析迟缓。全局变量的初始化值在编译时计算。

Var y:i32=add(10,x);const x:i32=add(12,34);test";全局变量";{assert(x==46);assert(y==56);}fn add(a:i32,b:i32)I32{return a+b;}const std=@import(";std";);const assert=std.debug.assert;

在其他编程语言中,空引用是许多运行时异常的根源,甚至被指责为计算机科学中最严重的错误。

$zig test test.zig./docgen_tmp/test.zig:2:17:错误:指针类型';*I32';不允许地址为零常量PTR=@intToPtr(*I32,0x0);^。

但是,任何类型都可以作为可选类型,只需在其前面加上?:

Const std=@import(";std";);const assert=std.debug.assert;test";null@intToPtr";{const ptr=@intToPtr(?*I32,0x0);assert(ptr==NULL);}。

//包含的用于参考外部FN Malloc的Malloc原型(大小:Size_t)?*U8;FN doATing()?*foo{const PTR=Malloc(1234)orelse return NULL;//...}。

Fn doATing(OPTIONAL_FOO:?*FOO)void{//如果(OPTIONAL_FOO)|foo|{doSomethingWithFoo(Foo);}//做一些事情}。

Const std=@import(";std";);pub fn main()void{const msg=";hello this is dog";;var it=std.mem.tokenize(msg;";";);While(it.next())|Items|{std.debug.print(";{}\n";,.{Item});}}。

为了实现这一点,Zig程序员必须管理他们自己的内存,并且必须处理内存分配失败。

Zig标准库也是如此。任何需要分配内存的函数都接受一个分配器参数。因此,Zig标准库甚至可以用于独立的目标。

除了全新的错误处理方式外,Zig还提供了延迟和错误延迟功能,使所有资源管理(不仅仅是内存)变得简单且易于验证。

有关延迟的示例,请参见在没有FFI/绑定的情况下与C库集成。以下是使用errdefer的示例:

Const device=struct{name:[]u8,fn create(allocator:*allocator,id:u32)!device{const device=try allocator.create(Device);errdeer allocator.destect(Device);device.name=try std.fmt.allocPrint(allocator,";device(id={})";,id);errer allocator.free(device.name);if(id==。

Const std=@import(";std";);pub fn main()void{const file=std.fs.cwd().openFile(";do_not_exist/foo.txt";,.{})Catch|err|Label:{std.debug.print(";Unable to open file:{}\n";,.{err});const stderr=std.ior。File.WriteAll(";您的所有代码库都属于我们\n&34;)Catch Return;}。

$zig build-exe catch.zig$./catch无法打开文件:error.FileNotFound您的所有代码库都属于我们。

Const std=@import(";std&34;);pub fn main()!Void{const file=try std.fs.cwd().openFile(";do_not_exist/foo.txt";,.{});推迟file.lose();try file.WriteAll(";您所有的代码库都属于我们\n";);}。

$zig build-exe try.zig$./try Error:std.os.openatZ(Try)中的FileNotFound/home/andy/Downloads/zig/lib/std/os.zig:1167:23:0x22a73b,enOENT=>;返回错误。FileNotFound,std.fs.Dir.openFileZ(Try)中的^/home/andy/Downloads/zig/lib/std/fs.zig:711:13:0x20c93a尝试os.openatZ(self.fd,Sub_Path,os_FLAGS,0);Std.fs.Dir.openFile(Try)中的^/home/andy/Downloads/zig/lib/std/fs.zig:651:9:0x20a93f返回self.openFileZ(&;路径_c,标志);主(Try)常量文件中的^/home/andy/dev/www.ziglang.org/docgen_tmp/try.zig:4:18:0x22f4b8=Try std.fs.cwd().openFile(";does_not_exist/foo.txt";,。{});^。

请注意,这是错误返回跟踪,而不是堆栈跟踪。该代码没有付出展开堆栈的代价来得出该跟踪。

Const std=@import(";std";);test";Switch on Error";{const Result=parseInt(";hi";,10)Catch|err|Switch(Err){};}fn parseInt(buf:[]const U8,基:U8)!U64{var x:u64=0;for(Buf)|c|{const digit=try charToDigit(C);if(digit>;=基){return error.DigitExceedsRadix;}x=try std.math.mul(U64,x,基);x=try std.math.add(U64,x,digit);}return x;}fn charToDigit(c:u8)!U8{Const Value=Switch(C){';0';...';9';=>;c-#39;0';...';Z';=>;c-#39;A';+10,';a';...';z';=>;c-';A';+10,否则=>;返回错误。InvalidCharacter,};返回值;}。

$zig test test.zig./docgen_tmp/test.zig:4:51:Error:error.Overflow Not Handling in Switch Const Result=parseInt(";hi";,10)Catch|err|Switch(Err){};^./docgen_tmp/test.zig:3:24:注意:引用的heretest";打开错误";{^./docgen_tmp/test.zig:嗨";,10)Catch|err|Switch(Err){};^./docgen_tmp/test.zig:4:51:错误:error.InvalidCharacter未在Switch Const Result=parseInt(";hi";,10)Catch|err|Switch(Err){};^中处理。

Const std=@import(";std";);pub fn main()void{const file=std.fs.cwd().openFile(";do_not_exist/foo.txt";,.{})Catch Unreacable;file.WriteAll(";您的所有代码库都属于我们\n";)Catch Unreacable;}。

$zig build-exe unachable.zig$./unachable尝试解包错误:std.os.openatZ(不可访问)中的FileNotFound/home/andy/Downloads/zig/lib/std/os.zig:1167:23:0x22a56b(不可访问)ENOENT=>;返回错误。FileNotFound,std.fs.Dir.openFileZ(不可访问)中的^/home/andy/Downloads/zig/lib/std/fs.zig:711:13:0x20c76a尝试os.openatZ(self.fd,SUB_PATH,os_。标准文件目录中的^/home/andy/Downloads/zig/lib/std/fs.zig:651:9:0x20a76f返回self.openFileZ(&;路径_c,标志);^?:0x206b6c in?(?)/home/andy/dev/www.ziglang.org/docgen_tmp/unreachable.zig:4:71:0x22f325 in Main(Unreacable)const file=std.fs.cwd().openFile(";Do_NOT_EXIST/foo.txt";,.{})Catch Unreacable;^/home/andy/Downloads/zig/lib/std/start.zig:242:22:0x2049ef in std.start.posxCallMainAndExit(Unreacable)root.main();^/home/andy/Downloads/zig/lib/std/start.zig:123:5:0x2047cf in std.star._start(Unreacable)@Call(.{.Modify=.Never_Inline},position xCallMainAndExit,.{});^(进程由信号终止。

这会在不安全的生成模式中调用未定义的行为,因此请确保只有在保证成功的情况下才使用它。

此页上显示的堆栈跟踪和错误返回跟踪适用于所有第1层支持和某些第2层支持目标。甚至是独立式的!

此外,标准库能够在任何时候捕获堆栈跟踪,然后将其转储为标准错误:

Const std=@import(";std";);const Builtin=@import(";Builtin";);var地址缓冲区:[8]usize=未定义;var trace1=builtin.StackTrace{.Instructions_Addresses=Address_Buffer[0.。4],.index=0,};var trace2=builtin.StackTrace{.Instruction_Addresses=Address_Buffer[4.],.index=0,};pub fn main()void{foo();bar();std.debug.print(";第一个:\n";,.{});std.debug.umpStackTrace(Trace1);std.debug.print(";\n\n第二个Std.debug.ump pStackTrace(Trace2);}fn foo()void{std.debug.captureStackTrace(NULL,&;trace1);}fn bar()void{std.debug.captureStackTrace(NULL,&;trace2);}

$zig build-exe STACK_Traces.zig$./STACK_TRACE第一个:/home/andy/Downloads/zig/lib/std/debug.zig:183:29:0x236d14 in std.debug.captureStackTrace(STACK_TRACE)add.*=it.next()orelse{^/home/andy/dev/www.ziglang.org/docgen_tmp/stack_traces.zig:27:32:0x23486c in foo(STACK_TRACE)std.debug.captureStackTrace(NULL,&;trace1);主(STACK_TRACE)foo()中的^/home/andy/dev/www.ziglang.org/docgen_tmp/stack_traces.zig:17:8:0x22f278;std.start.posxCallMainAndExit(STACK_TRACE)root.main()中的^/home/andy/Downloads/zig/lib/std/start.zig:242:22:0x2049cf;^第二个:/home/andy/Downloads/zig/lib/std/debug.zig:183:29:0x236d14 in std.debug.captureStackTrace(Stack_Traces)add.*=it.next()orrelse{^/home/andy/dev/www.ziglang.org/docgen_tmp/stack_traces.zig:31:32:0x23488c in bar(STACK_TRACE)std.debug.captureStackTrace(NULL,&;trace2);主(Stack_Traces)栏中的^/home/andy/dev/www.ziglang.org/docgen_tmp/stack_traces.zig:18:8:0x22f27d();std.start.posxCallMainAndExit(Stack_Traces)根中的^/home/andy/Downloads/zig/lib/std/start.zig:242:22:0x2049cf();^。

Const std=@import(";std";);const assert=std.debug.assert;test";类型为";{const t1=u8;const t2=bool;assert(t1!=t2);const x:t2=true;assert(X);}。

Const std=@import(";std&34;);fn list(comptime T:type)type{return struct{Items:[]T,len:usize,};}pub FN main()void{var Buffer:[10]I32=未定义;var List=List(I32){.Items=&;Buffer,.len=0,};std.debug.print(";{}\n";,.{list。

Const std=@import(";std";);const Header=struct{Magic:u32,name:[]const U8,};pub FN main()void{printInfoAboutStruct(Header);}fn printInfoAboutStruct(comptime T:type)void{const info=@typeInfo(T);inline for(info.Struct.field)|field|{std.debug.。,.{@typeName(T),field.name,@typeName(field.field_type),},);}}。

$zig build-exe refection.zig$./refectionHeader有一个名为Magic的字段,类型为u32Header有一个名为Name的字段,类型为[]const U8。

Zig标准库使用这种技术来实现格式化打印。尽管Zig是一种小而简单的语言,但Zig的格式化打印完全是用Zig实现的。同时,在C中,printf的编译错误被硬编码到编译器中。类似地,在Rust中,格式化的打印宏被硬编码到编译器中。

Zig还可以在编译时评估函数和代码块。在某些上下文中(如全局变量初始化),表达式在编译时隐式求值。否则,可以在编译时使用comptime关键字显式计算代码。当与断言结合使用时,这会特别强大:

Const std=@import(";std&34;);const assert=std.debug.assert;fn Fibonacci(x:u32)u32{if(x<;=1)return x;return Fibonacci(x-1)+Fibonacci(x-2);}test";编译时求值";{var数组:[Fibonacci(6)]I32=未定义;comptime{assertime

$zig测试测试。zig/home/andy/Downloads/zig/lib/std/debug.zig:223:14:错误:如果(!OK)无法访问,则无法计算常量表达式;//断言失败^./docgen_tmp/test.zig:13:15:注意:从此处调用断言(array.len==12345);^./docgen_tmp/test.zig:9:32:注意:从此处调用";编译时评估";{^./docgen_tmp/test.zig:13:15:注意:此处引用断言(array.len==12345);^。

@cImport直接导入类型、变量、函数和简单宏,以便在Zig中使用。它甚至将内联函数从C转换为Zig。

Const c=@cImport(@cInclude(";soundio/soundio.h&34;));const std=@import(";std";);fn sio_err(err:c_int)!Void{switch(@intToEnum(c.SoundIoError,Err)){.None=>;{},.NoMem=>;return error.NoMem,.InitAudioBackend=>;return error.InitAudioBackend=>;return error.SystemResources,.OpeningDevice=>;return error.OpeningDevice,.NoSuchDevice。返回错误。流,.InpatibleDevice=>;返回错误。不兼容设备,.NoSuchClient=>;返回错误。NoSuchClient,.InpatibleBackend=>;返回错误。不兼容后端,.BackendDisConnected=>;返回错误。BackendDisConnected,.Interrupted=>;返回错误。中断,.Underflow=>;返回错误。Fn WRITE_CALLBACK(可能_outstream:?[*]c.SoundIoOutStream,Frame_count_min:c_int,Frame_count_max:c_int,)callconv(.c)void{const outstream=@ptrCast(*c.SoundIoOutStream,可能_outstream);const Layout=&;outStre.layout;const Float_Sample_Rate=outStre.Sample_rate;const Second_per_Frame=1.0/@。而(FRAMES_LEFT>;0){var FRAME_COUNT=FRAMES_LEFT;var Area:[*]c.SoundIoChannelArea=未定义;SIO_ERR(c.soundio_outstream_egin_write(大概_outstream,@ptrCast([*]?[*]c.SoundIoChannelArea,&;Area),&;Frame_count,))Catch|err|std.debug.Panic(";IF(FRAME_COUNT==0)Break;Const Pitch=440.0;Const Radians_Per_Second=Pitch*2.0*std.math.pi;var Frame:C_int=0;While(Frame<;Frame_Count):(Frame+=1){const Sample=std.math.sin((Second_Offset+@intToFloat(F32,Frame)*Second_Per_Frame)*RADIANS_Per_Second)*RADIANS_Per_Second);{var Channel:usize=0。@intCast(usize,layout.Channel_count)):(Channel+=1){const CHANNEL_PTR=Areas[Channel].ptr;const Sample_PTR=&;Channel_ptr[@intCast(usize,Area[Channel].Step*Frame)];@ptrCast(*F32,@alignCast(@alignOf(F32),Sample_Ptr))。*=Sample;}Second_Offset+=(*F32,@alignCast(@alignOf(F32),Sample_Ptr))。*=Sample;}Second_Offset+=。Sio_err(c.soundio_outstream_end_write(maybe_outstream))Catch|err|std.debug.Panic(";结束写入失败:{}";,@errorName(Err));FRAMES_LEFT-=FRAME_COUNT;}}pub FN Main()!C.soundio_default_output_device_index(soundio);{const soundio=c.soundio_create();推迟c.soundio_DESTORE(Soundio);尝试sio_err(c.soundio_connect(Soundio));c.soundio_flush_events(Soundio);const DEFAULT_OUTPUT_INDEX=c.soundio_default_output_device_index(soundio);if(DEFAULT_OUTPUT_INDEX<;0)返回错误。NoOutputDeviceFound;const device=c.soundio_get_Output_device(soundio,默认。Defer c.soundio_device_unref(Device);std.debug.print(";输出设备:{s}\n";,.{([*]const U8)(device.*.name)});const outstream=c.soundio_outstream_create(Device)或返回错误.OutOfMemory;deferc.soundio_outstream_DESTORY(Outstream);outstream.*.format=c.SoundIo.*.格式=c.SoundIo.。尝试sio_err(c.soundio_outstream_start(outstream));While(True)c.Soundio_Wait_Events(Soundio);}。

这个Zig代码比同等的C代码简单得多,并且有更多的安全保护,所有这些都是通过直接导入C头文件来实现的--没有API绑定。

$zig build-exe--c-source hello.c--库c--Verbose-cczig cc-MD-mv-mf zig-cache/tmp/42zL6fBH8fSO-hello.o.d-nostdinc-fno拼写检查-issystem/home/andy/dev/zig/build/lib/zig/Include-issystem/home/andy/dev/zig/build/lib/zig/libc/include/x86_64-linux-gnu-issystem/home/andy/dev/zig/build/lib/zig/libc/include/generic-glibc。-issystem/home/andy/dev/zig/build/lib/zig/libc/include/x86_64-linux-any-issystem/home/andy/dev/zig/build/lib/zig/libc/include/any-linux-any-march=Native-g-f栈保护器-STRONG--param ssp-Buffer-Size=4-fno-omit-Frame-POINTER-o zig-cache/tmp/42zL6fBH8fSo-hello.o-c hello.c-fPic。

请注意,如果我再次运行该命令,则没有输出,并且

Zig的主要用例之一是用C ABI导出库,供其他编程语言调用。函数、变量和类型前面的EXPORT关键字会使它们成为库API的一部分:

.