On branch main

modified:   src/ch01.md
new file:   src/ex-ch01-03.zig
This commit is contained in:
zed
2023-11-10 12:22:18 +03:00
parent a035418c74
commit 9462460af6
2 changed files with 111 additions and 0 deletions

View File

@@ -390,3 +390,105 @@ const b = a[1..end];
И последнее - если бы мы написали `const end: usize = 4;`, а не `var end: usize = 4;`,
то опять получили бы не срез (указатель + длина), а указатель на массив.
Изучение Zig приучает к мысли, что типы весьма содержательны. Это не просто целое,
логическое или даже массив целых. Типы также содержат другую важную информацию.
Мы уже говорили о том, что длина массива является состоавляющей частью типа.
Многие примеры показывают, что неизменямость (constness) также является составляющей типа.
Например, в нашем последнем примере тип `b` это `[]const i32`. Вы можете сами
это наглядно увидеть при помощи вот такой программы:
```zig
const std = @import("std");
pub fn main() void {
const a = [_]i32{1, 2, 3, 4, 5};
var end: usize = 4;
const b = a[1..end];
std.debug.print("{any}", .{@TypeOf(b)});
}
```
Запустим её:
```
$ /opt/zig-0.11/zig run src/ex-ch01-03.zig
[]const i32
```
Если бы в этом примере мы попытались бы записать что-то в `b`,
например `b[2] = 1`, мы бы получили ошибку компиляции:
```
$ /opt/zig-0.11/zig run src/ex-ch01-03.zig
src/ex-ch01-03.zig:8:6: error: cannot assign to constant
b[2] = 1;
~^~~
```
Наверняка для исправления ситуации Вам тут хочется поменять `const` на `var`
при объявлении `b`:
```zig
// меняем const на var
var b = a[1..end];
```
Однако, к нашему удивлению, мы получим ту же самую ошибку. Как же так?
Дело в том, что указатель в срезе показывает на какую-то часть
конкретного массива и тип среза выводится из типа массива,
из которого берется срез. Поэтому вне зависимости от того, как объявлен
срез `b`, мутабельным (изменяемым, то есть как `var`) или нет (то есть как `const`),
он делает срез с `[5]const i32` и поэтому он обязан иметь точно такой же тип.
Если мы хотим менять содержимое массива `a` через его срез `b`, нужно писать так:
```zig
const std = @import("std");
pub fn main() void {
var a = [_]i32{1, 2, 3, 4, 5};
var end: usize = 4;
const b = a[1..end];
b[2] = 99;
}
```
Это работает, поскольку теперь тип среза `b` это `[]i32`, а не `[]const i32`,
как было до этого. Тут Вы справедливо возразите - но `b`-то у нас всё равно `const`,
как же тогда это может работать?!? Но всё просто - неизменяемость `b`
относится к самому `b` (то есть к той самой паре указатель+длина),
но не к данным, на которые он показывает, а показывает он на `var a`,
то есть на что-то мутабельное/изменяемое.
Для ясности попробуйте откомпилировать
```zig
const std = @import("std");
pub fn main() void {
var a = [_]i32{1, 2, 3, 4, 5};
var end: usize = 4;
const b = a[1..end];
b = b[1..];
}
```
Это компилятор не пропустит, потому что мы попытались переназначить
немутабельный срез. Если бы мы написали `var b = a[1..end];`, то всё было
бы нормально.
## Строки
Эх, хотелось бы тут сказать, что "в Zig есть тип `string` и он просто офигенный",
но, увы и ах, нет в Zig такого типа. А что же тогда есть? Строки в Zig -
это просто последовательности (массивы или срезы) байтов (`u8`). Мы уже
на самом деле видели это в самом начале, когда описывали поле `name` в
структуре `User` как `name: []const u8`.
По соглашению (и только по соглашению), такие строки должны содержать
только корректные с точки зрения UTF-8 значения, при этом сами исходные
тексты на Zig тоже кодируются при помощи UTF-8. Конечно же,
нет никакой разницы, что у нас размещается в `[]const u8`, произвольные
"бинарные" данные или строка в кодировке UTF-8. Как бы то ни было,
для всех случаев используется один и тот же тип, как для собственно строк,
так и для всего прочего.

9
src/ex-ch01-03.zig Normal file
View File

@@ -0,0 +1,9 @@
const std = @import("std");
pub fn main() void {
const a = [_]i32{1, 2, 3, 4, 5};
var end: usize = 4;
const b = a[1..end];
std.debug.print("{any}\n", .{@TypeOf(b)});
}