🎯 Рекомендуемые коллекции
Балансированные коллекции примеров кода из различных категорий, которые вы можете исследовать
Примеры Zig
Примеры языка программирования Zig - простое, эффективное системное программирование с безопасностью памяти
💻 Zig Hello World zig
🟢 simple
⭐⭐
Программа Hello World на Zig с фундаментальным синтаксисом и возможностями языка
⏱️ 15 min
🏷️ zig, programming, system, memory-safe
Prerequisites:
Basic programming concepts
// Zig Hello World Examples
// 1. Basic Hello World
const std = @import("std");
pub fn main() void {
std.debug.print("Hello, World!\n", .{});
}
// 2. Hello World with variables and types
pub fn helloWithVariables() void {
// String literals
const message1 = "Hello, World!";
const message2 = "Hello, Zig!";
std.debug.print("{s}\n", .{message1});
std.debug.print("{s}\n", .{message2});
// Basic data types
const integer: i32 = 42;
const unsigned_integer: u32 = 100;
const floating_point: f64 = 3.14159;
const boolean: bool = true;
const character: u8 = 'A';
std.debug.print("Integer: {}\n", .{integer});
std.debug.print("Unsigned: {}\n", .{unsigned_integer});
std.debug.print("Float: {d}\n", .{floating_point});
std.debug.print("Boolean: {}\n", .{boolean});
std.debug.print("Character: {c}\n", .{character});
}
// 3. Hello World with functions
fn sayHello() []const u8 {
return "Hello, World!";
}
fn greetUser(name: []const u8) []const u8 {
// Note: This is simplified - in real code you'd use proper string formatting
return "Hello!";
}
pub fn helloWithFunctions() void {
std.debug.print("{s}\n", .{sayHello()});
std.debug.print("{s}\n", .{greetUser("Zig")});
}
// 4. Hello World with structs
const User = struct {
name: []const u8,
age: u32,
fn greet(self: User) void {
std.debug.print("Hello, {s}! You are {} years old.\n", .{ self.name, self.age });
}
};
pub fn helloWithStructs() void {
const user = User{
.name = "Alice",
.age = 30,
};
user.greet();
}
// 5. Hello World with enums
const GreetingType = enum {
formal,
casual,
enthusiastic,
fn getText(self: GreetingType) []const u8 {
return switch (self) {
.formal => "Good day",
.casual => "Hello",
.enthusiastic => "Hey there!",
};
}
};
pub fn helloWithEnums() void {
const formal_greeting = GreetingType.formal;
const casual_greeting = GreetingType.casual;
const enthusiastic_greeting = GreetingType.enthusiastic;
std.debug.print("{s}, World!\n", .{formal_greeting.getText()});
std.debug.print("{s}, World!\n", .{casual_greeting.getText()});
std.debug.print("{s}, World!\n", .{enthusiastic_greeting.getText()});
}
// 6. Hello World with arrays and slices
pub fn helloWithArrays() void {
// Array (fixed size, known at compile time)
const greetings = [3][]const u8{
"Hello",
"Hola",
"Bonjour"
};
// Loop through array
for (greetings) |greeting| {
std.debug.print("{s}, World!\n", .{greeting});
}
// Slice (runtime-sized view into array)
const slice = greetings[0..2];
std.debug.print("Slice length: {}\n", .{slice.len});
}
// 7. Hello World with error handling
const GreetingError = error{
EmptyName,
InvalidAge,
};
fn createGreeting(name: []const u8, age: u32) ![]const u8 {
if (name.len == 0) return GreetingError.EmptyName;
if (age == 0) return GreetingError.InvalidAge;
// In real code, you'd use a proper allocator for string formatting
return "Hello!";
}
pub fn helloWithErrorHandling() void {
const result = createGreeting("Bob", 25);
if (result) |greeting| {
std.debug.print("{s}\n", .{greeting});
} else |err| {
std.debug.print("Error: {}\n", .{err});
}
}
// 8. Hello World with comptime (compile-time execution)
pub fn helloWithComptime() void {
// Comptime strings
const comptime_greeting = comptime "Hello from compile time!";
std.debug.print("{s}\n", .{comptime_greeting});
// Comptime function execution
const comptime_result = comptime addNumbers(5, 3);
std.debug.print("Comptime 5 + 3 = {}\n", .{comptime_result});
}
fn addNumbers(a: i32, b: i32) i32 {
return a + b;
}
// 9. Hello World with generic types
fn printGeneric(comptime T: type, value: T) void {
switch (@typeInfo(T)) {
.Int => std.debug.print("Integer: {}\n", .{value}),
.Float => std.debug.print("Float: {d}\n", .{value}),
.Bool => std.debug.print("Boolean: {}\n", .{value}),
else => std.debug.print("Other type\n", .{}),
}
}
pub fn helloWithGenerics() void {
const int_value: i32 = 42;
const float_value: f64 = 3.14;
const bool_value: bool = true;
printGeneric(i32, int_value);
printGeneric(f64, float_value);
printGeneric(bool, bool_value);
}
// 10. Hello World with optionals
fn findGreeting(id: u32) ?[]const u8 {
return switch (id) {
1 => "Hello",
2 => "Hola",
3 => "Bonjour",
else => null,
};
}
pub fn helloWithOptionals() void {
const greeting1 = findGreeting(1) orelse "Default greeting";
const greeting2 = findGreeting(99) orelse "Default greeting";
std.debug.print("Found: {s}\n", .{greeting1});
std.debug.print("Found: {s}\n", .{greeting2});
}
// Main function demonstrating all examples
pub fn main() void {
std.debug.print("=== Zig Hello World Examples ===\n\n");
std.debug.print("1. Basic Hello World:\n");
std.debug.print("Hello, World!\n\n");
std.debug.print("2. Variables and types:\n");
helloWithVariables();
std.debug.print("\n");
std.debug.print("3. Functions:\n");
helloWithFunctions();
std.debug.print("\n");
std.debug.print("4. Structs:\n");
helloWithStructs();
std.debug.print("\n");
std.debug.print("5. Enums:\n");
helloWithEnums();
std.debug.print("\n");
std.debug.print("6. Arrays and slices:\n");
helloWithArrays();
std.debug.print("\n");
std.debug.print("7. Error handling:\n");
helloWithErrorHandling();
std.debug.print("\n");
std.debug.print("8. Comptime execution:\n");
helloWithComptime();
std.debug.print("\n");
std.debug.print("9. Generic types:\n");
helloWithGenerics();
std.debug.print("\n");
std.debug.print("10. Optionals:\n");
helloWithOptionals();
std.debug.print("\n");
std.debug.print("=== All Zig Examples Completed ===\n");
}
💻 Управление памятью Zig zig
🟡 intermediate
⭐⭐⭐⭐
Продвинутое управление памятью в Zig включая аллокаторы, срезы и безопасность памяти
⏱️ 25 min
🏷️ zig, memory, allocators, system-programming
Prerequisites:
Basic Zig syntax and pointers
// Zig Memory Management Examples
const std = @import("std");
// 1. Stack allocation
pub fn stackAllocation() void {
std.debug.print("=== Stack Allocation ===\n");
// Variables allocated on stack (automatically managed)
var number: i32 = 42;
var boolean: bool = true;
var array: [10]u8 = .{0} ** 10;
array[0] = 1;
array[1] = 2;
std.debug.print("Stack number: {}\n", .{number});
std.debug.print("Stack array: {any}\n", .{array[0..5]});
std.debug.print("Memory freed automatically when function exits\n\n");
}
// 2. Heap allocation with allocator
pub fn heapAllocation(allocator: std.mem.Allocator) !void {
std.debug.print("=== Heap Allocation ===\n");
// Allocate slice on heap
const slice = try allocator.alloc(u8, 10);
defer allocator.free(slice);
// Initialize the slice
for (slice, 0..) |*byte, i| {
byte.* = @intCast(i + 1);
}
std.debug.print("Heap slice: {any}\n", .{slice});
std.debug.print("Slice length: {}\n", .{slice.len});
std.debug.print("Slice capacity: {}\n", .{slice.capacity});
std.debug.print("Memory will be freed by defer\n\n");
}
// 3. Custom allocator example
const CustomAllocator = struct {
const Self = @This();
buffer: [1024]u8,
offset: usize,
pub fn init() Self {
return Self{
.buffer = std.mem.zeroes([1024]u8),
.offset = 0,
};
}
pub fn allocator(self: *Self) std.mem.Allocator {
return .{
.ptr = self,
.vtable = &.{
.alloc = alloc,
.resize = resize,
.free = free,
},
};
}
fn alloc(ctx: *anyopaque, len: usize, log2_align: u8, ret_addr: usize) ?[*]u8 {
_ = log2_align;
_ = ret_addr;
const self: *Self = @ptrCast(@alignCast(ctx));
if (self.offset + len > self.buffer.len) return null;
const result = self.buffer[self.offset..][0..len];
self.offset += len;
return result.ptr;
}
fn resize(ctx: *anyopaque, old_mem: []u8, log2_align: u8, new_len: usize) bool {
_ = ctx;
_ = old_mem;
_ = log2_align;
_ = new_len;
return false; // Simple allocator doesn't support resizing
}
fn free(ctx: *anyopaque, old_mem: []u8, log2_align: u8, ret_addr: usize) void {
_ = ctx;
_ = old_mem;
_ = log2_align;
_ = ret_addr;
// This simple allocator doesn't actually free memory
}
};
pub fn customAllocatorDemo() !void {
std.debug.print("=== Custom Allocator Demo ===\n");
var custom_alloc = CustomAllocator.init();
const allocator = custom_alloc.allocator();
const slice = try allocator.alloc(u8, 20);
defer allocator.free(slice);
for (slice, 0..) |*byte, i| {
byte.* = @intCast(i % 256);
}
std.debug.print("Custom allocated slice: {any}\n", .{slice[0..10]});
std.debug.print("Allocator offset: {}\n", .{custom_alloc.offset});
std.debug.print("\n");
}
// 4. Arena allocator
pub fn arenaAllocatorDemo() !void {
std.debug.print("=== Arena Allocator Demo ===\n");
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// Multiple allocations that will be freed all at once
const slice1 = try allocator.alloc(u8, 100);
const slice2 = try allocator.alloc(i32, 50);
const slice3 = try allocator.alloc(f64, 25);
std.debug.print("Allocated {} bytes for slice1\n", .{slice1.len});
std.debug.print("Allocated {} integers for slice2\n", .{slice2.len});
std.debug.print("Allocated {} floats for slice3\n", .{slice3.len});
std.debug.print("All memory freed when arena is destroyed\n\n");
}
// 5. Fixed buffer allocator
pub fn fixedBufferAllocatorDemo() !void {
std.debug.print("=== Fixed Buffer Allocator Demo ===\n");
var buffer: [1024]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
const slice = try allocator.alloc(u8, 100);
defer allocator.free(slice);
for (slice, 0..) |*byte, i| {
byte.* = @intCast((i * 2) % 256);
}
std.debug.print("Fixed buffer slice: {any}\n", .{slice[0..20]});
std.debug.print("Remaining buffer space: {} bytes\n", .{fba.end_index});
std.debug.print("\n");
}
// 6. Memory-safe string operations
pub fn safeStringOperations(allocator: std.mem.Allocator) !void {
std.debug.print("=== Safe String Operations ===\n");
// Safe string concatenation
const str1 = "Hello";
const str2 = ", ";
const str3 = "Zig!";
const result = try std.mem.concat(allocator, u8, &[_][]const u8{ str1, str2, str3 });
defer allocator.free(result);
std.debug.print("Concatenated: {s}\n", .{result});
// Safe string duplication
const duplicated = try allocator.dupe(u8, result);
defer allocator.free(duplicated);
std.debug.print("Duplicated: {s}\n", .{duplicated});
// Safe string comparison
const are_equal = std.mem.eql(u8, result, duplicated);
std.debug.print("Strings equal: {}\n\n", .{are_equal});
}
// 7. Working with slices
pub fn sliceOperations(allocator: std.mem.Allocator) !void {
std.debug.print("=== Slice Operations ===\n");
// Create a slice
const original = try allocator.alloc(i32, 10);
defer allocator.free(original);
for (original, 0..) |*item, i| {
item.* = @intCast(i * 10);
}
std.debug.print("Original slice: {any}\n", .{original});
// Slice the slice
const sub_slice = original[2..7];
std.debug.print("Sub slice [2..7]: {any}\n", .{sub_slice});
// Duplicate slice
const duplicated = try allocator.dupe(i32, sub_slice);
defer allocator.free(duplicated);
std.debug.print("Duplicated sub slice: {any}\n", .{duplicated});
// Resize slice
const resized = try allocator.realloc(original, 15);
defer allocator.free(resized);
for (resized[10..]) |*item| {
item.* = 999;
}
std.debug.print("Resized slice: {any}\n\n", .{resized});
}
// 8. Memory layout and struct packing
const PackedStruct = extern struct {
a: u8,
b: u32,
c: u8,
};
const UnpackedStruct = struct {
a: u8,
b: u32,
c: u8,
};
pub fn memoryLayoutDemo() void {
std.debug.print("=== Memory Layout Demo ===\n");
std.debug.print("Size of packed struct: {} bytes\n", .{@sizeOf(PackedStruct)});
std.debug.print("Size of unpacked struct: {} bytes\n", .{@sizeOf(UnpackedStruct)});
const packed = PackedStruct{ .a = 1, .b = 0x12345678, .c = 2 };
const unpacked = UnpackedStruct{ .a = 1, .b = 0x12345678, .c = 2 };
std.debug.print("Packed struct values: a={}, b=0x{x}, c={}\n", .{ packed.a, packed.b, packed.c });
std.debug.print("Unpacked struct values: a={}, b=0x{x}, c={}\n\n", .{ unpacked.a, unpacked.b, unpacked.c });
}
// 9. COMTIME memory allocation
pub fn comptimeMemoryDemo() void {
std.debug.print("=== Comptime Memory Demo ===\n");
// Comptime allocation for compile-time constants
const comptime_numbers = comptime blk: {
var result: [10]usize = undefined;
for (&result, 0..) |*item, i| {
item.* = i * i;
}
break :blk result;
};
std.debug.print("Comptime squares: {any}\n", .{comptime_numbers});
// Comptime string building
const comptime_string = comptime std.fmt.comptimePrint("The answer is {}", .{42});
std.debug.print("Comptime string: {s}\n\n", .{comptime_string});
}
// Main function demonstrating all memory management examples
pub fn main() !void {
const gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
std.debug.print("=== Zig Memory Management Examples ===\n\n");
stackAllocation();
try heapAllocation(allocator);
try customAllocatorDemo();
try arenaAllocatorDemo();
try fixedBufferAllocatorDemo();
try safeStringOperations(allocator);
try sliceOperations(allocator);
memoryLayoutDemo();
comptimeMemoryDemo();
std.debug.print("=== All Memory Examples Completed ===\n");
// Check for memory leaks
const leaked = gpa.detectLeaks();
if (leaked) {
std.debug.print("Memory leaks detected!\n");
}
}
💻 Конкурентность Zig zig
🔴 complex
⭐⭐⭐⭐⭐
Паттерны конкурентности в Zig включая async/await, потоки и каналы
⏱️ 30 min
🏷️ zig, concurrency, async, threads, system
Prerequisites:
Advanced Zig syntax and system programming
// Zig Concurrency and Async Examples
const std = @import("std");
// 1. Basic async/await
pub fn basicAsyncDemo() !void {
std.debug.print("=== Basic Async Demo ===\n");
// Async function that simulates work
const asyncWork = struct {
fn doWork(value: u32) u32 {
std.time.sleep(100 * std.time.ns_per_ms);
return value * 2;
}
}.doWork;
// Call async function and await result
const frame = try std.heap.page_allocator.create(@Frame(asyncWork));
defer std.heap.page_allocator.destroy(frame);
frame.* = async asyncWork(21);
const result = await frame;
std.debug.print("Async result: {}\n\n", .{result});
}
// 2. Multiple async operations
pub fn multipleAsyncDemo() !void {
std.debug.print("=== Multiple Async Demo ===\n");
const asyncTask = struct {
fn computeSquare(n: u32) u32 {
std.time.sleep(50 * std.time.ns_per_ms);
return n * n;
}
fn computeCube(n: u32) u32 {
std.time.sleep(75 * std.time.ns_per_ms);
return n * n * n;
}
};
// Create frames for async operations
const square_frame = try std.heap.page_allocator.create(@Frame(asyncTask.computeSquare));
const cube_frame = try std.heap.page_allocator.create(@Frame(asyncTask.computeCube));
defer std.heap.page_allocator.destroy(square_frame);
defer std.heap.page_allocator.destroy(cube_frame);
// Start async operations
square_frame.* = async asyncTask.computeSquare(5);
cube_frame.* = async asyncTask.computeCube(3);
// Wait for results
const square_result = await square_frame;
const cube_result = await cube_frame;
std.debug.print("Square of 5: {}\n", .{square_result});
std.debug.print("Cube of 3: {}\n\n", .{cube_result});
}
// 3. Thread-based concurrency
const WorkerTask = struct {
id: u32,
result: u32,
fn compute(self: *WorkerTask) void {
std.debug.print("Worker {} started\n", .{self.id});
std.time.sleep(200 * std.time.ns_per_ms);
self.result = self.id * 100;
std.debug.print("Worker {} finished with result {}\n", .{self.id, self.result});
}
};
pub fn threadDemo() !void {
std.debug.print("=== Thread Demo ===\n");
var workers: [4]WorkerTask = undefined;
var threads: [4]std.Thread = undefined;
// Create and start threads
for (&workers, 0..) |*worker, i| {
worker.* = WorkerTask{
.id = @intCast(i + 1),
.result = 0,
};
threads[i] = try std.Thread.spawn(.{}, WorkerTask.compute, .{worker});
}
// Wait for all threads to complete
for (threads) |thread| {
thread.join();
}
// Collect results
var total: u32 = 0;
for (workers) |worker| {
total += worker.result;
}
std.debug.print("Total from all workers: {}\n\n", .{total});
}
// 4. Simple channel implementation
const Channel = struct {
const Self = @This();
const T = u32;
buffer: [10]T,
head: usize,
tail: usize,
count: usize,
mutex: std.Thread.Mutex,
condition: std.Thread.Condition,
pub fn init() Self {
return Self{
.buffer = std.mem.zeroes([10]T),
.head = 0,
.tail = 0,
.count = 0,
.mutex = std.Thread.Mutex{},
.condition = std.Thread.Condition{},
};
}
pub fn send(self: *Self, value: T) void {
self.mutex.lock();
defer self.mutex.unlock();
while (self.count == self.buffer.len) {
self.condition.wait(&self.mutex);
}
self.buffer[self.tail] = value;
self.tail = (self.tail + 1) % self.buffer.len;
self.count += 1;
self.condition.signal();
}
pub fn receive(self: *Self) T {
self.mutex.lock();
defer self.mutex.unlock();
while (self.count == 0) {
self.condition.wait(&self.mutex);
}
const value = self.buffer[self.head];
self.head = (self.head + 1) % self.buffer.len;
self.count -= 1;
self.condition.signal();
return value;
}
};
const ProducerTask = struct {
channel: *Channel,
id: u32,
fn run(self: *ProducerTask) void {
for (0..5) |i| {
const value = self.id * 10 + @as(u32, @intCast(i));
std.debug.print("Producer {} sending {}\n", .{ self.id, value });
self.channel.send(value);
std.time.sleep(50 * std.time.ns_per_ms);
}
}
};
const ConsumerTask = struct {
channel: *Channel,
received: u32,
fn init(channel: *Channel) ConsumerTask {
return ConsumerTask{
.channel = channel,
.received = 0,
};
}
fn run(self: *ConsumerTask) void {
while (self.received < 10) {
const value = self.channel.receive();
std.debug.print("Consumer received {}\n", .{value});
self.received += 1;
std.time.sleep(30 * std.time.ns_per_ms);
}
}
};
pub fn channelDemo() !void {
std.debug.print("=== Channel Demo ===\n");
var channel = Channel.init();
var producer1 = ProducerTask{ .channel = &channel, .id = 1 };
var producer2 = ProducerTask{ .channel = &channel, .id = 2 };
var consumer = ConsumerTask.init(&channel);
// Create threads for producer-consumer pattern
const producer1_thread = try std.Thread.spawn(.{}, ProducerTask.run, .{&producer1});
const producer2_thread = try std.Thread.spawn(.{}, ProducerTask.run, .{&producer2});
const consumer_thread = try std.Thread.spawn(.{}, ConsumerTask.run, .{&consumer});
// Wait for all threads to complete
producer1_thread.join();
producer2_thread.join();
consumer_thread.join();
std.debug.print("Channel demo completed\n\n");
}
// 5. Async event loop simulation
const EventType = enum {
timer,
message,
shutdown,
};
const Event = struct {
type: EventType,
data: u32,
};
const EventLoop = struct {
const Self = @This();
events: std.ArrayList(Event),
running: bool,
pub fn init(allocator: std.mem.Allocator) Self {
return Self{
.events = std.ArrayList(Event).init(allocator),
.running = true,
};
}
pub fn deinit(self: *Self) void {
self.events.deinit();
}
pub fn addEvent(self: *Self, event: Event) !void {
try self.events.append(event);
}
pub fn run(self: *Self) !void {
std.debug.print("Event loop started\n");
while (self.running) {
if (self.events.items.len > 0) {
const event = self.events.orderedRemove(0);
switch (event.type) {
.timer => {
std.debug.print("Processing timer event with data {}\n", .{event.data});
},
.message => {
std.debug.print("Processing message event with data {}\n", .{event.data});
},
.shutdown => {
std.debug.print("Processing shutdown event\n");
self.running = false;
},
}
} else {
std.time.sleep(10 * std.time.ns_per_ms);
}
}
std.debug.print("Event loop stopped\n");
}
};
pub fn eventLoopDemo() !void {
std.debug.print("=== Event Loop Demo ===\n");
const gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var event_loop = EventLoop.init(allocator);
defer event_loop.deinit();
try event_loop.addEvent(Event{ .type = .message, .data = 1 });
try event_loop.addEvent(Event{ .type = .timer, .data = 100 });
try event_loop.addEvent(Event{ .type = .message, .data = 2 });
try event_loop.addEvent(Event{ .type = .shutdown, .data = 0 });
try event_loop.run();
std.debug.print("\n");
}
// 6. Atomic operations for lock-free programming
pub fn atomicDemo() void {
std.debug.print("=== Atomic Operations Demo ===\n");
var counter: std.atomic.Value(u32) = std.atomic.Value(u32).init(0);
// Increment atomically
const old_value = counter.fetchAdd(1, .Monotonic);
std.debug.print("Old value: {}, New value: {}\n", .{ old_value, counter.load(.Monotonic) });
// Compare and swap
const expected: u32 = 1;
const new_value: u32 = 100;
const swapped = counter.cmpxchgWeak(expected, new_value, .Monotonic, .Monotonic);
if (swapped) {
std.debug.print("Compare and swap succeeded\n");
} else {
std.debug.print("Compare and swap failed\n");
}
std.debug.print("Final value: {}\n\n", .{counter.load(.Monotonic)});
}
// 7. Coroutine-style generators
const NumberGenerator = struct {
const Self = @This();
current: u32,
max: u32,
pub fn init(max: u32) Self {
return Self{
.current = 0,
.max = max,
};
}
pub fn next(self: *Self) ?u32 {
if (self.current >= self.max) return null;
const result = self.current;
self.current += 1;
return result;
}
};
pub fn generatorDemo() void {
std.debug.print("=== Generator Demo ===\n");
var generator = NumberGenerator.init(5);
while (generator.next()) |number| {
std.debug.print("Generated number: {}\n", .{number});
}
std.debug.print("Generator exhausted\n\n");
}
// Main function demonstrating all concurrency examples
pub fn main() !void {
const gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
defer _ = gpa.deinit();
std.debug.print("=== Zig Concurrency and Async Examples ===\n\n");
try basicAsyncDemo();
try multipleAsyncDemo();
try threadDemo();
try channelDemo();
try eventLoopDemo();
atomicDemo();
generatorDemo();
std.debug.print("=== All Concurrency Examples Completed ===\n");
}