Zig 爲什麼可以判斷兩個類型相等?
最近在和一些朋友線下交流,分享 Zig 時,都不約而同的提了一個問題,Zig 是如何判斷下面這兩個類型是一樣的:
fn LinkedList(comptime T: type) type {
return struct {
pub const Node = struct {
prev: ?*Node,
next: ?*Node,
data: T,
};
first: ?*Node,
last: ?*Node,
len: usize,
};
}
test "linked list" {
try expect(LinkedList(i32) == LinkedList(i32));
}
我們知道,類型在 Zig 中是一等成員,和 i8、f32 類似,那上面調用了兩次 LinkedList(i32)
,爲什麼他們會是相等的呢?僅僅因爲他們包含的字段一樣?
在動態語言裏,這其實叫做 Duck Typing[1],即鴨子類型,一個在 Python 中的例子:
class Duck:
def swim(self):
print("Duck swimming")
def fly(self):
print("Duck flying")
class Whale:
def swim(self):
print("Whale swimming")
for animal in [Duck(), Whale()]:
animal.swim()
animal.fly()
輸出
Duck swimming
Duck flying
Whale swimming
AttributeError: 'Whale' object has no attribute 'fly'
如果因爲鴨子會游泳,所以可以假設任何會游泳的東西都是鴨子,那麼鯨魚就可以被認爲是鴨子; 然而,如果還假設鴨子必須會飛,那麼鯨魚就不會被認爲是鴨子。
爲了簡化 Zig 中的問題,定義以下兩個類型:
const StaticA = struct { foo: i8 };
pub fn main() !void {
const dynamic_struct = std.builtin.Type.Struct{
.layout = .Auto,
.fields = &[1]std.builtin.Type.StructField{.{
.name = "foo",
.type = i8,
.default_value = null,
.is_comptime = false,
.alignment = 1,
}},
.decls = &.{},
.is_tuple = false,
};
const DynamicA = @Type(.{ .Struct = dynamic_struct });
try std.testing.expect(DynamicA == StaticA);
}
上述代碼通過兩種方式生成了具有相同字段的兩個類型,都只有一個字段,且名字類型一致,但最後 expect
會報錯,說明這是兩個不同的類型,即便他們具有相同的字段。
那麼一開始的例子裏,爲什麼兩個 LinkedList(i32)
會被認爲相等呢?這其實是由於 Zig 的一種特殊實現,即在 comptime 期間執行的函數,結果會緩存下來,因此兩次調用返回的是同一值,所以他們相等。
引用鏈接
[1]
Duck Typing: https://en.wikipedia.org/wiki/Duck_typing
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/a-c0dmWuMJ1RmgRgf6RrJg