mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-05-05 14:28:31 +00:00
Merge pull request #4872 from verhovsky/zig
[zig/en] mark Zig code as zig
This commit is contained in:
commit
e680a6bd13
@ -5,24 +5,19 @@ contributors:
|
|||||||
- ["Philippe Pittoli", "https://karchnu.fr/"]
|
- ["Philippe Pittoli", "https://karchnu.fr/"]
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
[Zig][ziglang] aims to be a replacement for the C programming language.
|
[Zig][ziglang] aims to be a replacement for the C programming language.
|
||||||
|
|
||||||
**WARNING**: this document expects you to understand a few basic concepts in computer science, such as pointers, stack and heap memory, etc.
|
**WARNING**: this document expects you to understand a few basic concepts in computer science, such as pointers, stack and heap memory, etc.
|
||||||
|
|
||||||
**WARNING**: Zig isn't considered as ready for production. Bugs are expected.
|
**WARNING**: Zig isn't considered as ready for production. Bugs are expected.
|
||||||
DO NOT TRY ZIG AS YOUR FIRST PROGRAMMING EXPERIENCE.
|
|
||||||
The compiler, even the language and its libraries aren't ready, yet.
|
|
||||||
You've been warned.
|
|
||||||
|
|
||||||
Prior knowledge of C is recommended.
|
Prior knowledge of C is recommended.
|
||||||
|
|
||||||
|
|
||||||
## Quick overview: Zig compared to C
|
## Quick overview: Zig compared to C
|
||||||
|
|
||||||
- Syntax is mostly the same, with some improvements (less ambiguity).
|
- Syntax is mostly the same, with some improvements (less ambiguity).
|
||||||
- Zig introduces namespaces.
|
- Zig introduces namespaces.
|
||||||
- Try and catch mechanism, which is both convenient, efficient and optional.
|
- `try` and `catch` mechanism, which is both convenient, efficient and optional.
|
||||||
- Most of the C undefined behaviors (UBs) are fixed.
|
- Most of the C undefined behaviors (UBs) are fixed.
|
||||||
- Compared to C, raw pointers are safer to use and less likely to be needed.
|
- Compared to C, raw pointers are safer to use and less likely to be needed.
|
||||||
* The type system distinguishes between a pointer to a single value, or multiple values, etc.
|
* The type system distinguishes between a pointer to a single value, or multiple values, etc.
|
||||||
@ -38,8 +33,7 @@ Prior knowledge of C is recommended.
|
|||||||
|
|
||||||
## Zig language
|
## Zig language
|
||||||
|
|
||||||
|
```zig
|
||||||
```
|
|
||||||
//! Top-level documentation.
|
//! Top-level documentation.
|
||||||
|
|
||||||
/// Documentation comment.
|
/// Documentation comment.
|
||||||
@ -47,9 +41,9 @@ Prior knowledge of C is recommended.
|
|||||||
// Simple comment.
|
// Simple comment.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Hello world.
|
### Hello world.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
// Import standard library, reachable through the "std" constant.
|
// Import standard library, reachable through the "std" constant.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
@ -67,7 +61,8 @@ pub fn main() void {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Booleans, integers and float.
|
### Booleans, integers and float.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
// Booleans.
|
// Booleans.
|
||||||
// Keywords are preferred to operators for boolean operations.
|
// Keywords are preferred to operators for boolean operations.
|
||||||
print("{}\n{}\n{}\n", .{
|
print("{}\n{}\n{}\n", .{
|
||||||
@ -109,7 +104,8 @@ i <<| 8 == 255 // u8: won't go higher than 255
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Arrays.
|
### Arrays.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
// An array is a well-defined structure with a length attribute (len).
|
// An array is a well-defined structure with a length attribute (len).
|
||||||
|
|
||||||
// 5-byte array with undefined content (stack garbage).
|
// 5-byte array with undefined content (stack garbage).
|
||||||
@ -156,8 +152,8 @@ try some_integers[i]; // Runtime error 'index out of bounds'.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Multidimensional arrays.
|
### Multidimensional arrays.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
const mat4x4 = [4][4]f32{
|
const mat4x4 = [4][4]f32{
|
||||||
[_]f32{ 1.0, 0.0, 0.0, 0.0 },
|
[_]f32{ 1.0, 0.0, 0.0, 0.0 },
|
||||||
[_]f32{ 0.0, 1.0, 0.0, 1.0 },
|
[_]f32{ 0.0, 1.0, 0.0, 1.0 },
|
||||||
@ -177,8 +173,8 @@ for (mat4x4) |row, row_index| {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Strings.
|
### Strings.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// Simple string constant.
|
// Simple string constant.
|
||||||
const greetings = "hello";
|
const greetings = "hello";
|
||||||
// ... which is equivalent to:
|
// ... which is equivalent to:
|
||||||
@ -195,8 +191,8 @@ print("string: {s}\n", .{greetings});
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Slices.
|
### Slices.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// A slice is a pointer and a size, an array without compile-time known size.
|
// A slice is a pointer and a size, an array without compile-time known size.
|
||||||
// Slices have runtime out-of-band verifications.
|
// Slices have runtime out-of-band verifications.
|
||||||
|
|
||||||
@ -206,8 +202,8 @@ const slice = array[0..array.len]; // "slice" represents the whole array.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Pointers.
|
### Pointers.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// Pointer on a value can be created with "&".
|
// Pointer on a value can be created with "&".
|
||||||
const x: i32 = 1;
|
const x: i32 = 1;
|
||||||
const pointer: *i32 = &x; // "pointer" is a pointer on the i32 var "x".
|
const pointer: *i32 = &x; // "pointer" is a pointer on the i32 var "x".
|
||||||
@ -223,7 +219,8 @@ const foo = pointer.?; // Get the pointed value, otherwise crash.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Optional values (?<type>).
|
### Optional values (?<type>).
|
||||||
```
|
|
||||||
|
```zig
|
||||||
// An optional is a value than can be of any type or null.
|
// An optional is a value than can be of any type or null.
|
||||||
|
|
||||||
// Example: "optional_value" can either be "null" or an unsigned 32-bit integer.
|
// Example: "optional_value" can either be "null" or an unsigned 32-bit integer.
|
||||||
@ -239,7 +236,8 @@ if (x) |value| {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Errors.
|
### Errors.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
// Zig provides an unified way to express errors.
|
// Zig provides an unified way to express errors.
|
||||||
|
|
||||||
// Errors are defined in error enumerations, example:
|
// Errors are defined in error enumerations, example:
|
||||||
@ -299,7 +297,7 @@ var value = try some_function();
|
|||||||
|
|
||||||
### Control flow.
|
### Control flow.
|
||||||
|
|
||||||
```
|
```zig
|
||||||
// Conditional branching.
|
// Conditional branching.
|
||||||
|
|
||||||
if (condition) {
|
if (condition) {
|
||||||
@ -384,8 +382,8 @@ const result = for (items) |value| {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Labels.
|
### Labels.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// Labels are a way to name an instruction, a location in the code.
|
// Labels are a way to name an instruction, a location in the code.
|
||||||
// Labels can be used to "continue" or "break" in a nested loop.
|
// Labels can be used to "continue" or "break" in a nested loop.
|
||||||
outer: for ([_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }) |_| {
|
outer: for ([_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }) |_| {
|
||||||
@ -434,8 +432,8 @@ const result = for (items) |value| { // First: loop.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Switch.
|
### Switch.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// As a switch in C, but slightly more advanced.
|
// As a switch in C, but slightly more advanced.
|
||||||
// Syntax:
|
// Syntax:
|
||||||
// switch (value) {
|
// switch (value) {
|
||||||
@ -454,15 +452,15 @@ var x = switch(value) {
|
|||||||
// A slightly more advanced switch, accepting a range of values:
|
// A slightly more advanced switch, accepting a range of values:
|
||||||
const foo: i32 = 0;
|
const foo: i32 = 0;
|
||||||
const bar = switch (foo) {
|
const bar = switch (foo) {
|
||||||
0 => "zero",
|
0 => "zero",
|
||||||
1...std.math.maxInt(i32) => "positive",
|
1...std.math.maxInt(i32) => "positive",
|
||||||
else => "negative",
|
else => "negative",
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Structures.
|
### Structures.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// Structure containing a single value.
|
// Structure containing a single value.
|
||||||
const Full = struct {
|
const Full = struct {
|
||||||
number: u16,
|
number: u16,
|
||||||
@ -564,7 +562,8 @@ print("p.y: {}\n", .{p.y}); // 30
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Tuples.
|
### Tuples.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
// A tuple is a list of elements, possibly of different types.
|
// A tuple is a list of elements, possibly of different types.
|
||||||
|
|
||||||
const foo = .{ "hello", true, 42 };
|
const foo = .{ "hello", true, 42 };
|
||||||
@ -572,33 +571,33 @@ const foo = .{ "hello", true, 42 };
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Enumerations.
|
### Enumerations.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
const Type = enum { ok, not_ok };
|
const Type = enum { ok, not_ok };
|
||||||
|
|
||||||
const CardinalDirections = enum { North, South, East, West };
|
const CardinalDirections = enum { North, South, East, West };
|
||||||
const direction: CardinalDirections = .North;
|
const direction: CardinalDirections = .North;
|
||||||
const x = switch (direction) {
|
const x = switch (direction) {
|
||||||
// shorthand for CardinalDirections.North
|
// shorthand for CardinalDirections.North
|
||||||
.North => true,
|
.North => true,
|
||||||
else => false
|
else => false
|
||||||
};
|
};
|
||||||
|
|
||||||
// Switch statements need exhaustiveness.
|
// Switch statements need exhaustiveness.
|
||||||
// WARNING: won't compile. East and West are missing.
|
// WARNING: won't compile. East and West are missing.
|
||||||
const x = switch (direction) {
|
const x = switch (direction) {
|
||||||
.North => true,
|
.North => true,
|
||||||
.South => true,
|
.South => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Switch statements need exhaustiveness.
|
// Switch statements need exhaustiveness.
|
||||||
// Won't compile: East and West are missing.
|
// Won't compile: East and West are missing.
|
||||||
const x = switch (direction) {
|
const x = switch (direction) {
|
||||||
.North => true,
|
.North => true,
|
||||||
.South => true,
|
.South => true,
|
||||||
.East, // Its value is the same as the following pattern: false.
|
.East, // Its value is the same as the following pattern: false.
|
||||||
.West => false,
|
.West => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -606,12 +605,12 @@ const x = switch (direction) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Unions.
|
### Unions.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
const Bar = union {
|
const Bar = union {
|
||||||
boolean: bool,
|
boolean: bool,
|
||||||
int: i16,
|
int: i16,
|
||||||
float: f32,
|
float: f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Both syntaxes are equivalent.
|
// Both syntaxes are equivalent.
|
||||||
@ -622,8 +621,8 @@ const foo: Bar = .{ .int = 42 };
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Tagged unions.
|
### Tagged unions.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// Unions can be declared with an enum tag type, allowing them to be used in
|
// Unions can be declared with an enum tag type, allowing them to be used in
|
||||||
// switch expressions.
|
// switch expressions.
|
||||||
|
|
||||||
@ -653,8 +652,8 @@ switch (nay) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Defer and errdefer.
|
### Defer and errdefer.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// Make sure that an action (single instruction or block of code) is executed
|
// Make sure that an action (single instruction or block of code) is executed
|
||||||
// before the end of the scope (function, block of code).
|
// before the end of the scope (function, block of code).
|
||||||
// Even on error, that action will be executed.
|
// Even on error, that action will be executed.
|
||||||
@ -695,24 +694,25 @@ Thus, the standard library lets developers handle memory as they need, through s
|
|||||||
**NOTE**: the choice of the allocator isn't in the scope of this document.
|
**NOTE**: the choice of the allocator isn't in the scope of this document.
|
||||||
A whole book could be written about it.
|
A whole book could be written about it.
|
||||||
However, here are some examples, to get an idea of what you can expect:
|
However, here are some examples, to get an idea of what you can expect:
|
||||||
- page_allocator.
|
- `page_allocator`.
|
||||||
Allocate a whole page of memory each time we ask for some memory.
|
Allocate a whole page of memory each time we ask for some memory.
|
||||||
Very simple, very dumb, very wasteful.
|
Very simple, very dumb, very wasteful.
|
||||||
- GeneralPurposeAllocator.
|
- `GeneralPurposeAllocator`.
|
||||||
Get some memory first and manage some buckets of memory in order to
|
Get some memory first and manage some buckets of memory in order to
|
||||||
reduce the number of allocations.
|
reduce the number of allocations.
|
||||||
A bit complex. Can be combined with other allocators.
|
A bit complex. Can be combined with other allocators.
|
||||||
Can detect leaks and provide useful information to find them.
|
Can detect leaks and provide useful information to find them.
|
||||||
- FixedBufferAllocator.
|
- `FixedBufferAllocator`.
|
||||||
Use a fixed buffer to get its memory, don't ask memory to the kernel.
|
Use a fixed buffer to get its memory, don't ask memory to the kernel.
|
||||||
Very simple, limited and wasteful (can't deallocate), but very fast.
|
Very simple, limited and wasteful (can't deallocate), but very fast.
|
||||||
- ArenaAllocator.
|
- `ArenaAllocator`.
|
||||||
Allow to free all allocated memory at once.
|
Allow to free all allocated memory at once.
|
||||||
To use in combinations with another allocator.
|
To use in combinations with another allocator.
|
||||||
Very simple way of avoiding leaks.
|
Very simple way of avoiding leaks.
|
||||||
|
|
||||||
A first example.
|
A first example.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
// "!void" means the function doesn't return any value except for errors.
|
// "!void" means the function doesn't return any value except for errors.
|
||||||
// In this case we try to allocate memory, and this may fail.
|
// In this case we try to allocate memory, and this may fail.
|
||||||
fn foo() !void {
|
fn foo() !void {
|
||||||
@ -735,8 +735,8 @@ fn foo() !void {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Memory allocation combined with error management and defer.
|
### Memory allocation combined with error management and defer.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
fn some_memory_allocation_example() !void {
|
fn some_memory_allocation_example() !void {
|
||||||
// Memory allocation may fail, so we "try" to allocate the memory and
|
// Memory allocation may fail, so we "try" to allocate the memory and
|
||||||
// in case there is an error, the current function returns it.
|
// in case there is an error, the current function returns it.
|
||||||
@ -759,8 +759,8 @@ fn some_memory_allocation_example() !void {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Memory allocators: a taste of the standard library.
|
### Memory allocators: a taste of the standard library.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// Allocators: 4 main functions to know
|
// Allocators: 4 main functions to know
|
||||||
// single_value = create (type)
|
// single_value = create (type)
|
||||||
// destroy (single_value)
|
// destroy (single_value)
|
||||||
@ -846,8 +846,8 @@ fn gpa_arena_allocator_fn() !void {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Comptime.
|
### Comptime.
|
||||||
```
|
|
||||||
|
|
||||||
|
```zig
|
||||||
// Comptime is a way to avoid the pre-processor.
|
// Comptime is a way to avoid the pre-processor.
|
||||||
// The idea is simple: run code at compilation.
|
// The idea is simple: run code at compilation.
|
||||||
|
|
||||||
@ -883,7 +883,8 @@ list.items[0] = 10;
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Conditional compilation.
|
### Conditional compilation.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
const available_os = enum { OpenBSD, Linux };
|
const available_os = enum { OpenBSD, Linux };
|
||||||
const myos = available_os.OpenBSD;
|
const myos = available_os.OpenBSD;
|
||||||
|
|
||||||
@ -905,7 +906,8 @@ const myprint = switch(myos) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Testing our functions.
|
### Testing our functions.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const expect = std.testing.expect;
|
const expect = std.testing.expect;
|
||||||
|
|
||||||
@ -936,45 +938,44 @@ There are more than a hundred built-ins, allowing very low-level stuff:
|
|||||||
- etc.
|
- etc.
|
||||||
|
|
||||||
Example: enums aren't integers, they have to be converted with a built-in.
|
Example: enums aren't integers, they have to be converted with a built-in.
|
||||||
```
|
|
||||||
|
```zig
|
||||||
const Value = enum { zero, stuff, blah };
|
const Value = enum { zero, stuff, blah };
|
||||||
if (@enumToInt(Value.zero) == 0) { ... }
|
if (@enumToInt(Value.zero) == 0) { ... }
|
||||||
if (@enumToInt(Value.stuff) == 1) { ... }
|
if (@enumToInt(Value.stuff) == 1) { ... }
|
||||||
if (@enumToInt(Value.blah) == 2) { ... }
|
if (@enumToInt(Value.blah) == 2) { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### A few "not yourself in the foot" measures in the Zig language.
|
### A few "not yourself in the foot" measures in the Zig language.
|
||||||
|
|
||||||
- Namespaces: names conflicts are easily avoided.
|
- Namespaces: name conflicts are easily avoided.
|
||||||
In practice, that means an unified API between different structures (data types).
|
In practice, that means a unified API between different structures (data types).
|
||||||
- Enumerations aren't integers. Comparing an enumeration to an integer requires a conversion.
|
- Enumerations aren't integers. Comparing an enumeration to an integer requires a conversion.
|
||||||
- Explicit casts, coercion exists but is limited.
|
- Explicit casts, coercion exists but is limited.
|
||||||
Types are slightly more enforced than in C, just a taste:
|
Types are slightly more enforced than in C, just a taste:
|
||||||
Pointers aren't integers, explicit conversion is necessary.
|
Pointers aren't integers, explicit conversion is necessary.
|
||||||
You won't lose precision by accident, implicit coercions are only authorized in case no precision can be lost.
|
You won't lose precision by accident, implicit coercions are only authorized in cases where no precision can be lost.
|
||||||
Unions cannot be reinterpreted (in an union with an integer and a float, one cannot take a value for another by accident).
|
Unions cannot be reinterpreted (in a union with an integer and a float, one cannot take a value for another by accident).
|
||||||
Etc.
|
Etc.
|
||||||
- Removing most of the C undefined behaviors (UBs), and when the compiler encounters one, it stops.
|
- Removing most of the C undefined behaviors (UBs), and when the compiler encounters one, it stops.
|
||||||
- Slice and Array structures are preferred to pointers.
|
- Slice and Array structures are preferred to pointers.
|
||||||
Types enforced by the compiler are less prone to errors than pointer manipulations.
|
Types enforced by the compiler are less prone to errors than pointer manipulations.
|
||||||
- Numerical overflows produce an error, unless explicitly accepted using wrapping operators.
|
- Numerical overflows produce an error, unless explicitly accepted using wrapping operators.
|
||||||
- Try and catch mechanism.
|
- `try` and `catch` mechanism.
|
||||||
It's both handy, trivially implemented (simple error enumeration), and it takes almost no space nor computation time.
|
It's both handy, trivially implemented (simple error enumeration), and it takes almost no space nor computation time.
|
||||||
- Unused variables are considered as errors by the compiler.
|
- Unused variables are considered to be errors by the compiler.
|
||||||
- Many pointer types exist in order to represent what is pointed.
|
- Many pointer types exist in order to represent what is pointed to.
|
||||||
Example: is this a single value or an array, is the length known, etc.
|
Example: is this a single value or an array, is the length known, etc.
|
||||||
- Structures need a value for their attributes, and it still is possible to give an undefined value (stack garbage), but at least it is explicitly undefined.
|
- Structures need a value for their attributes, and it is still possible to give an undefined value (stack garbage), but at least it is explicitly undefined.
|
||||||
|
|
||||||
|
|
||||||
## Further Reading
|
## Further Reading
|
||||||
|
|
||||||
For a start, some concepts are presented on the [Zig learn website][ziglearn].
|
For a start, some concepts are presented on [zig.guide][zigguide].
|
||||||
|
|
||||||
The [official website][zigdoc] provides a reference documentation to the language.
|
The [official website][zigdoc] provides the reference documentation of the language. The standard library [has its own documentation][zigstd].
|
||||||
|
|
||||||
For now, documentation for standard library is WIP.
|
|
||||||
|
|
||||||
[ziglang]: https://ziglang.org
|
[ziglang]: https://ziglang.org
|
||||||
[ziglearn]: https://ziglearn.org/
|
[zigguide]: https://zig.guide/
|
||||||
[zigdoc]: https://ziglang.org/documentation/
|
[zigdoc]: https://ziglang.org/documentation/
|
||||||
|
[zigstd]: https://ziglang.org/documentation/master/std/
|
||||||
|
Loading…
Reference in New Issue
Block a user