On branch main
modified: src/ch01.md new file: src/ex-ch01-03.zig
This commit is contained in:
102
src/ch01.md
102
src/ch01.md
@@ -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
9
src/ex-ch01-03.zig
Normal 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)});
|
||||
}
|
||||
Reference in New Issue
Block a user