Post

Zig Note - 01

Zig Note - 01

定义type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// enum
pub const Mapping = enum {
    lorom,
    hirom,
    exhirom,
    unknown,
};

// struct 
pub const RomHeader = struct {
    title: [21]u8,

    map_mode: u8,
    cartridge_type: u8,
    rom_size_code: u8,
    ram_size_code: u8,
    region_code: u8,
    developer_id: u8,
    version: u8,

    checksum_complement: u16,
    checksum: u16,

    reset_vector: u16,
};

// custom error type
const RomError = error{
    HeaderOutOfBounds,
    InvalidValues,
    ChecksumMismatch,
};

闭包

1
2
3
4
5
for (title) |c| {
    if (c < 0x20 or c > 0x7d) {
        return error.InvalidValues;
    }
}

函数返回可能的Error & 处理

返回值类型前加 ! 表示可能返回Error

1
2
3
4
// This function may return Error
fn parse_internal_header(data: []const u8, header_offset: u32) !RomHeader {
    ...
}

调用函数的时候,可以用下列方式捕获:

1
2
3
4
5
6
if(parse_internal_header(data, offset)) |parsed_header| {
    ... // success
} 
else |err| {
    ... // error
}

也可以使用catch关键词,只有当前面的结果出现了error后,才会向后执行. 利用该关键字可以将下列逻辑:

1
2
3
4
5
6
7
8
9
10
11
var parsed_header: RomHeader = undefined;

if (parse_internal_header(data, rom_start + 0x7fc0)) |header| {
    parsed_header = header;
} else if (parse_internal_header(data, rom_start + 0xffc0)) |header| {
    parsed_header = header;
} else if (parse_internal_header(data, rom_start + 0x40FFC0)) |header| {
    parsed_header = header;
} else {
    ... // all failed
}

简化成:

1
const parsed_header = 

zig block

如果被包进了{}中,就要在后面加分号。但是下面的语句会创建两个变量,并没有赋给rom_data

1
2
3
4
5
6
7
8
9
10
const rom_data: []const u8 =
    if (data_length % 1024 == 512){
        data[512..];
    }
    else if (data_length % 1024 == 0){
        data[0..];
    }
    else {
        return error.InvalidValue; // Error
    };

正确写法:

1
2
3
4
5
6
7
8
const rom_data: []const u8 =
    if (data_length % 1024 == 512)
        data[512..]
    else if (data_length % 1024 == 0)
        data[0..]
    else {
        return error.InvalidValue; // Error
    };

comptime_int

1
2
const size = 1 << 10;   // 合法
const size2 = 1 << header.rom_size_code; // 非法

单独写一个1时,属于zig中的comptime_int,它没有固定的位数,可以任意增长. 第一个例子中,因为二者都是固定的数值,所以可以在编译期间确定;但是后一个例子却不行.

解决方法是使用固定长度的1:

1
const size = @as(usize, 1) << @intCast(header.rom_size_code);

explict type

尽管 .{}能够推断类型,但是建立在周围的环境提供了确定类型的前提下。不要以为可以通过{}内的字段来推断!

比如下面的rom_info没有写具体类型,会报错:error: expected type 'src.parser.parser.RomHeader', found 'src.parser.parser.parse_internal_header__struct_43088

1
2
3
4
5
6
7
8
9
fn parse_internal_header(data: []const u8, header_offset: u32) !RomInfo {
    ......

    const rom_info = .{
        ......
    };

    return rom_info;
}

加上具体类型后解决.

1
2
3
4
5
6
7
8
9
fn parse_internal_header(data: []const u8, header_offset: u32) !RomInfo {
    ......

    const rom_info: RomInfo = .{
        ......
    };

    return rom_info;
}
This post is licensed under CC BY 4.0 by the author.