From 942b250895581f01adf52b3d5addd99b7a4bc0d3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 4 Dec 2017 01:42:02 -0500 Subject: [PATCH] update docs regarding enums and unions --- doc/langref.html.in | 211 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 163 insertions(+), 48 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 76bf0ce237..e5b896410d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -2096,30 +2096,38 @@ const Type = enum { NotOk, }; -// Enums are sum types, and can hold more complex data of different types. -const ComplexType = enum { - Ok: u8, - NotOk: void, -}; - // Declare a specific instance of the enum variant. -const c = ComplexType.Ok { 0 }; +const c = Type.Ok; -// The ordinal value of a simple enum with no data members can be -// retrieved by a simple cast. -// The value starts from 0, counting up for each member. -const Value = enum { +// If you want access to the ordinal value of an enum, you +// can specify the tag type. +const Value = enum(u2) { Zero, One, Two, }; + +// Now you can cast between u2 and Value. +// The ordinal value starts from 0, counting up for each member. test "enum ordinal value" { - assert(usize(Value.Zero) == 0); - assert(usize(Value.One) == 1); - assert(usize(Value.Two) == 2); + assert(u2(Value.Zero) == 0); + assert(u2(Value.One) == 1); + assert(u2(Value.Two) == 2); } -// Enums can have methods, the same as structs. +// You can override the ordinal value for an enum. +const Value2 = enum(u32) { + Hundred = 100, + Thousand = 1000, + Million = 1000000, +}; +test "set enum ordinal value" { + assert(u32(Value2.Hundred) == 100); + assert(u32(Value2.Thousand) == 1000); + assert(u32(Value2.Million) == 1000000); +} + +// Enums can have methods, the same as structs and unions. // Enum methods are not special, they are only namespaced // functions that you can call with dot syntax. const Suit = enum { @@ -2128,26 +2136,120 @@ const Suit = enum { Diamonds, Hearts, - pub fn ordinal(self: &const Suit) -> u8 { - u8(*self) + pub fn isClubs(self: Suit) -> bool { + return self == Suit.Clubs; } }; test "enum method" { const p = Suit.Spades; - assert(p.ordinal() == 1); + assert(!p.isClubs()); } // An enum variant of different types can be switched upon. -// The associated data can be retrieved using `|...|` syntax. -// -// A void type is not required on a tag-only member. const Foo = enum { - String: []const u8, - Number: u64, + String, + Number, None, }; test "enum variant switch" { - const p = Foo.Number { 54 }; + const p = Foo.Number; + const what_is_it = switch (p) { + Foo.String => "this is a string", + Foo.Number => "this is a number", + Foo.None => "this is a none", + }; + assert(mem.eql(u8, what_is_it, "this is a number")); +} + +// @TagType can be used to access the integer tag type of an enum. +const Small = enum { + One, + Two, + Three, + Four, +}; +test "@TagType" { + assert(@TagType(Small) == u2); +} + +// @memberCount tells how many fields an enum has: +test "@memberCount" { + assert(@memberCount(Small) == 4); +} + +// @memberName tells the name of a field in an enum: +test "@memberName" { + assert(mem.eql(u8, @memberName(Small, 1), "Two")); +} + +// @tagName gives a []const u8 representation of an enum value: +test "@tagName" { + assert(mem.eql(u8, @tagName(Small.Three), "Three")); +} +

TODO extern enum

+

TODO packed enum

+
$ zig test enum.zig
+Test 1/8 enum ordinal value...OK
+Test 2/8 set enum ordinal value...OK
+Test 3/8 enum method...OK
+Test 4/8 enum variant switch...OK
+Test 5/8 @TagType...OK
+Test 6/8 @memberCount...OK
+Test 7/8 @memberName...OK
+Test 8/8 @tagName...OK
+

See also:

+ +

union

+
const assert = @import("std").debug.assert;
+const mem = @import("std").mem;
+
+// A union has only 1 active field at a time.
+const Payload = union {
+    Int: i64,
+    Float: f64,
+    Bool: bool,
+};
+test "simple union" {
+    var payload = Payload {.Int = 1234};
+    // payload.Float = 12.34; // ERROR! field not active
+    assert(payload.Int == 1234);
+    // You can activate another field by assigning the entire union.
+    payload = Payload {.Float = 12.34};
+    assert(payload.Float == 12.34);
+}
+
+// Unions can be given an enum tag type:
+const ComplexTypeTag = enum { Ok, NotOk }; 
+const ComplexType = union(ComplexTypeTag) {
+    Ok: u8,
+    NotOk: void,
+};
+
+// Declare a specific instance of the union variant.
+test "declare union value" {
+    const c = ComplexType { .Ok = 0 };
+    assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
+}
+
+// @TagType can be used to access the enum tag type of a union.
+test "@TagType" {
+    assert(@TagType(ComplexType) == ComplexTypeTag);
+}
+
+// Unions can be made to infer the enum tag type.
+const Foo = union(enum) {
+    String: []const u8,
+    Number: u64,
+
+    // void can be omitted when inferring enum tag type.
+    None,
+};
+test "union variant switch" {
+    const p = Foo { .Number = 54 };
     const what_is_it = switch (p) {
         // Capture by reference
         Foo.String => |*x| {
@@ -2156,6 +2258,7 @@ test "enum variant switch" {
 
         // Capture by value
         Foo.Number => |x| {
+            assert(x == 54);
             "this is a number"
         },
 
@@ -2163,38 +2266,50 @@ test "enum variant switch" {
             "this is a none"
         }
     };
+    assert(mem.eql(u8, what_is_it, "this is a number"));
 }
 
-// The @memberName and @memberCount builtin functions can be used to
-// the string representation and number of members respectively.
-const BuiltinType = enum {
-    A: f32,
-    B: u32,
-    C,
+// TODO union methods
+
+
+const Small = union {
+    A: i32,
+    B: bool,
+    C: u8,
 };
 
-test "enum builtins" {
-    assert(mem.eql(u8, @memberName(BuiltinType.A { 0 }), "A"));
-    assert(mem.eql(u8, @memberName(BuiltinType.C), "C"));
-    assert(@memberCount(BuiltinType) == 3);
+// @memberCount tells how many fields a union has:
+test "@memberCount" {
+    assert(@memberCount(Small) == 3);
+}
+
+// @memberName tells the name of a field in an enum:
+test "@memberName" {
+    assert(mem.eql(u8, @memberName(Small, 1), "B"));
+}
+
+// @tagName gives a []const u8 representation of an enum value,
+// but only if the union has an enum tag type.
+const Small2 = union(enum) {
+    A: i32,
+    B: bool,
+    C: u8,
+};
+test "@tagName" {
+    assert(mem.eql(u8, @tagName(Small2.C), "C"));
 }
-
$ zig test enum.zig
-Test 1/4 enum ordinal value...OK
-Test 2/4 enum method...OK
-Test 3/4 enum variant switch...OK
-Test 4/4 enum builtins...OK
+
$ zig test union.zig
+Test 1/7 simple union...OK
+Test 2/7 declare union value...OK
+Test 3/7 @TagType...OK
+Test 4/7 union variant switch...OK
+Test 5/7 @memberCount...OK
+Test 6/7 @memberName...OK
+Test 7/7 @tagName...OK

- Enums are generated as a struct with a tag field and union field. Zig + Unions with an enum tag are generated as a struct with a tag field and union field. Zig sorts the order of the tag and union field by the largest alignment.

-

See also:

- -

union

-

TODO union documentation

switch

const assert = @import("std").debug.assert;
 const builtin = @import("builtin");