我们在家中有特性
最近我有更多的时间用 Zig [1] 编写代码,这对我的灵魂是有益的。我想分享一些我在 Zig 中对于抽象的见解,包括一些我发现有用但未被广泛使用的技术。关于 Zig 接口,已经有相当多的墨水 [2] 被洒在上面,这也是合理的。尽管不是语言特性,接口是 Zig 中实现运行时多态性的事实标准方法。然而,关于 Zig 的 comptime 的讨论更多,如何利用它来避免动态调度的性能问题并编写简洁的数据驱动代码。简而言之,Zig 中的多态性通常有两种方式:动态接口:使用不透明指针、虚表和动态调度实现运行时多态性。编译时鸭子类型:使用类型反射、开关语句和在编译时的单态性实现静态多态性。这种状态迄今为止已被证明是非常有效的,但并非没有其权衡。接口提供了我们在其他语言中习惯的类型契约。接受接口的函数对其方法签名有保证,但对其实现没有保证。然而,由于接口在设计上是模块化的,因此也会给编译器引入一个硬性障碍,从而导致性能开销。间接性足够大,以至于它往往无法有效地应用于它适用于单态代码的优化。在对性能敏感的代码的情况下,Zig 代码通常依赖于编译时鸭子类型。函数参数既可以是任何类型,也可以通过类型参数 T 进行参数化,函数实现将执行编译时反射或对类型的方法进行假设,这些假设可以在编译时进行检查。实现可以像 C++ 模板或 C 宏一样进行单态化。这比运行时鸭子类型稍微安全一些,因为任何接口违规将在编译时而不是运行时被捕获,但调用者和被调用者仍然必须小心记录和遵循可以传递哪些类型的契约。如果您来自其他强类型语言,您可能会觉得这种安排相当简单。这可能是设计使然——Zig 旨在保持简单。然而,如果您已经习惯了 Rust 的特性或 Haskell 类型类,那么在 Zig 中似乎并没有现成的等价物。我将争辩说,经过一点适应,在 Zig 用户空间中完美地表达类似的类型抽象是完全可能的。我建议在 Zig 中将编译时类型契约定义为特性的一个新惯例。它不需要任何库或机制——实际上它非常适合基础的 Zig。它灵感来自于一般的函数式编程世界,特别是 OCaml。定义:特性是一个编译时结构,包含与给定类型相关的函数。[9] 为了不埋没重点,让我从一个简单的示例开始,说明我们可能如何定义一个用于折叠(归约)类型的特性。/// T 在空值和组合操作下形成一个 Reducer fn Reducer (T : type) type { return struct { empty : T , combine : fn (T , T) T , fn reduce (self : @This () , xs : [] const T) T { var accum = self.empty ; for (xs) | x | accum = self.combine(accum , x) ; return accum ; } } ; } /// i32 在 0 和加法下形成一个求和归约器 const sum_trait = impl (Reducer (i32) , struct { pub const empty = 0 ; pub fn combine (x : T , y : T) T { return x + y ; } }) ; /// i32 在 1 和乘法下形成一个乘积归约器 const product_trait = impl (Reducer (i32) , struct { pub const empty = 1 ; pub fn combine (x : T , y : T) T { return x * y ; } }) ; export fn run (buf : [*c] i32 , n : usize) i32 { const sum = sum_trait.reduce(buf[0 .. n]) ; const product = product_trait.reduce(buf[0 .. n]) ; return sum + product ; } 唉。这不是非常顺滑吗? [10] 契约非常清晰,LSP 自动补全会捕捉到它,编译器甚至知道内联它并展开循环。特性就像是函数和类型的容器,告诉接收函数如何执行它不负责定义的子任务。它们的行为与虚表非常相似,唯一的区别是它们在编译时而不是运行时被评估。传统多态性与特性为了证明特性,让我们通过一个常见的动机示例来探索 Zig 的多态性:算术操作。多年来,我听到了一些抱怨,关于在用户定义类型上进行数学运算的尴尬。由于明确控制流的追求,Zig 放弃了运算符重载,这在来自其他类型语言的人看来可能是令人不适的。我们设想有一些用户定义的类型,如有理数和复数,并且我们想定义它们的基本算术操作。我们最终可能会得到如下内容。
阅读全文 →本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡