Menu

Zero 基本类型:整数、浮点数、Bool、String 和 Void

Zero 开箱即用的内置类型:各种宽度的有符号和无符号整数、浮点数、布尔值、字符、字符串,以及空类型 Void。

内置类型

Zero 提供了一组小而规整的基本类型。没有奇特的东西,也没有意外:只有每门系统语言都需要的那些类型,命名也保持一致。

类别类型说明
有符号整数i8、i16、i32、i64补码表示。
无符号整数u8、u16、u32、u64只有 0 和正数。
指针宽度usize、isize宽度与平台指针一致。
浮点数f32、f64IEEE-754。
布尔值booltrue 或 false。
字符char单个 Unicode 标量值。
字符串StringUTF-8 字符串。
空类型Void“没有有用的值。”

这就是你日常会用到的全部基本类型。复合类型,比如 shape、枚举 和 choice,都是由它们组合而成的。

整数

整数类型遵循统一的命名规则:i 表示有符号,u 表示无符号,后面跟位宽。所以 i32 是 32 位有符号整数,u8 是无符号字节,i64 是 64 位有符号整数。

let small_signed: i8   = -120
let byte:         u8   = 250
let id:           i32  = 1
let big:          i64  = 9_000_000_000
let index:        usize = 0

没有后缀的字面量默认是 i32,除非周围的上下文要求别的类型:

let answer = 42       // i32

需要特定宽度时,可以给字面量加后缀,或者标注绑定的类型:

let byte = 250_u8     // typed literal
let byte: u8 = 250    // typed binding

两种写法得到的值相同。当你直接把字面量传给函数或构造结构体时,字面量后缀的写法很方便:

let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }

该选哪种宽度

一个简单的经验法则:

  • 大多数有符号运算用 i32。 它的范围足够覆盖几乎所有需要计数的场景,在各个平台上都很快。
  • 字节级操作用 u8。 文件中的字节、缓冲区里的字节、网络上传输的字节。
  • 在意范围的非负计数用 u32 / u64。 比如超过 2 GB 的文件偏移量、很大的计数。
  • 大小和索引用 usize。 它是指针宽度的,与平台寻址内存所用的宽度一致。
  • 自纪元以来的时间之类用 i64。 足够以纳秒为单位表示几百年。

选能容纳数据的最小类型是好习惯;但类型选得太小导致溢出,比宽了一位要严重得多。

布尔值

let ok = true
let done: bool = false

bool 只有两个值:true 和 false。它们是字面量,不是需要从别处导入的常量。if 或 while 的条件就是一个 bool:整数和字符串不会被隐式当作真假值。

if ok {
    check world.out.write("yes\n")
} else {
    check world.out.write("no\n")
}

If/else 会详细介绍条件语句。

浮点数

f32 和 f64 分别是 32 位和 64 位的 IEEE-754 浮点数。需要小数时用它们,比如测量值、比例和几何计算。如果要对货币做精确运算,请用最小单位(分、聪)的整数,而不是浮点数。

let ratio: f32 = 0.5
let pi:    f64 = 3.141592653589793

没有后缀的浮点字面量默认是 f64。

字符和字符串

char 保存单个 Unicode 标量值:

let initial: char = 'Z'

String 是字符序列,标准库通常把它编码为 UTF-8。字符串字面量使用双引号:

let message: String = "hello from zero\n"

常见的转义序列都能用:\n 表示换行,\t 表示制表符,\\ 表示反斜杠本身,\" 表示双引号本身。

let multi_line = "line one\nline two\n"

标准库为字符串提供了字节级视图,方便做底层操作。std.mem.span("zero") 会返回一个覆盖这些字节的 Span<u8>,在解析、计算哈希或按字节比较时很有用。

Void

Void 是 Zero 表示“没有有用返回值”的类型。为副作用而存在的函数会使用它:

pub fun main(world: World) -> Void raises {
    check world.out.write("hello\n")
}

main 写出一些内容就返回了。没有值需要交回,所以类型是 Void。大多数接触 World 的函数都会用 Void:调用它们是为了效果,而不是结果。

数字字面量中的下划线

较长的数字字面量可以用下划线作视觉分隔。编译器会忽略它们,所以这纯粹是为了可读性:

let big   = 9_000_000_000_i64
let bytes = 1_048_576_u32     // 1 MiB

只要数字长到不好数,随便在哪里加都行。

类型化字面量后缀速查表

后缀类型示例
_i8 / _i16 / _i32 / _i64有符号整数127_i8
_u8 / _u16 / _u32 / _u64无符号整数255_u8
_usize / _isize指针宽度0_usize
_f32 / _f64浮点数0.5_f32

当周围的上下文无法确定类型时,构造值就可以用这些后缀。

下一步:函数

光有基本类型,没有处理它们的手段,也派不上用场。下一篇文档介绍 Zero 中的 函数:怎样声明函数、从函数返回值,以及把它们组合起来构建真正的程序。

常见问题

Zero 有哪些基本类型?

Zero 自带固定宽度的有符号整数 i8、i16、i32、i64;无符号整数 u8、u16、u32、u64;指针宽度的整数 usize 和 isize;浮点数 f32 和 f64;bool;char;String;以及用于不返回有用值的函数的 Void。

Zero 默认的整数类型是什么?

像 42 这样没有后缀的整数字面量默认是 i32,除非上下文要求别的类型。要使用特定宽度,可以给字面量加后缀,比如 42_u8 或 42_i64,也可以显式标注绑定的类型:let count: u8 = 42。

Zero 有单独的字符串类型吗?

有。像 "hello" 这样的字符串字面量属于内置的字符串类型,标准库把它当作字节序列(通常是 UTF-8)。如果要做更底层的字节操作,标准库提供了 span 和字节级工具;如果要按字符操作,可以用 char 表示单个标量值。

Zero 中的 Void 是什么意思?

Void 是不产生有用值的函数的返回类型,这类函数只为副作用而存在。约定的 pub fun main(world: World) -> Void raises 签名使用 Void,因为 main 的作用是做 I/O 然后退出,而不是产生一个值。

Zero 中 i32 和 u32 有什么区别?

i32 是 32 位有符号整数,范围是 −2,147,483,648 到 2,147,483,647。u32 是无符号的,范围是 0 到 4,294,967,295。负数有意义时用有符号类型;负数一旦出现就意味着 bug 时,比如计数、索引、大小等,用无符号类型。

Coddy 编程语言插图

和 Coddy 一起学编程

开始