变量与类型

Toka 是一门具有丰富类型系统的静态类型语言。让我们来探索变量和类型是如何工作的。

变量声明

使用 auto 关键字声明变量:

auto x = 10          // i32(默认整数类型)
auto y = 3.14        // f64(默认浮点类型)
auto name = "Toka"   // str(字符串切片)

命名规则与连字符(-)消歧

Toka 对连字符(-)字符有一套严格而优雅的规则,在实现模块化命名便利性的同时,确保数学语法没有歧义。

包名与命名空间

import 的文件系统路径段可以使用连字符。进入 Toka 语义命名空间的名字——包括 import alias 和调用点使用的 namespace——必须是普通 identifier,因此对 kebab-case 路径应使用下划线别名:

import std/io::println

// 路径可以有连字符;别名不可以。
import ./nested/toka-ink as toka_ink

fn main() -> i32 {
    toka_ink::render()
    return 0
}

变量与函数

普通变量名、常量名、shape/结构体名和函数定义不能包含连字符。它们必须遵循标准的字母数字/下划线命名规则(如 camelCasesnake_case):

fn main() -> i32 {
    auto max_size = 1024       // OK(snake_case)
    auto maxSize = 1024        // OK(camelCase)
    // auto max-size = 1024    // 错误:变量名中不允许使用连字符
    return 0
}

无歧义的减法运算

由于连字符在变量名和函数名中是严格禁止的,减法运算符(-)没有歧义。为保持词法边界清晰,二元减法两侧必须写空格:

import std/io::println

fn main() -> i32 {
    auto sub1 = 10
    auto sub2 = 3
    
    auto result = sub1 - sub2
    auto value = 10 - 3
    println("Result: {}, Value: {}", result, value)
    return 0
}

显式类型标注

auto 总是推断绑定类型,不能在声明侧携带类型注解。要约束推断,请在初始化表达式后使用 : Type 类型归属:

auto x = 10:u64
auto y = 3.14:f32
auto flag = true:bool

缺失不是一种类型

Toka 1.0 明确区分三种缺失域:可空 handle 使用 nul *Tnul ^Tnul ~T,空值为 null;可空 payload 使用 T?none;操作结果的缺失使用 Option<T>::None。它们不会相互隐式转换。对所选的可空层使用 guard??,后缀 ! 只用于传播 OptionResult

基本类型

Toka 的类型系统在 lib/core/types.tk 中定义,包含:

类型描述大小
i8, i16, i32, i64有符号整数1-8 字节
u8, u16, u32, u64无符号整数1-8 字节
f32, f64浮点数(IEEE 754)4-8 字节
bool布尔值(true / false1 字节
charC 风格字符(i81 字节
byte原始字节(u81 字节

平台相关类型

pub alias usize = u64   // 指针大小的无符号整数
pub alias isize = i64   // 指针大小的有符号整数

在 64 位系统上,usizeu64;在 32 位系统上,它会是 u32

类型别名

Toka 支持两种类型别名:

弱别名(Weak alias) — 语义上完全相同,对编译器透明:

pub alias usize = u64

强类型(Strong type) — 内存布局相同,但需要显式转换:

pub type Addr = u64
pub type OAddr = u64

常量

使用 const 声明编译时常量值:

pub const MAX_SIZE = 1024:u64
pub const NAME = "Toka"

常量在编译时内联展开——不分配内存,不能获取其地址。

可变性

变量默认不可变。使用 # 后缀使其可变。# 标记仅在两个地方需要:

  1. 声明时 — 标记变量为可变
  2. 调用可变方法前 — 在变量上出示守卫
import std/io::println

pub shape List(data: i32)
impl List {
    pub fn sort(self#) {}
    pub fn push(self#, val: i32) {}
}

fn main() -> i32 {
    auto y = List(data = 10)  // 不可变
    auto x# = List(data = 10) // 可变 — 声明时加 #

    // 读取和赋值不需要 #
    x = List(data = 20)       // OK — 普通赋值
    println("{}", x.data)     // OK — 普通读取

    // 调用可变方法需要在变量上加 #
    x#.sort()                 // OK — 调用 .method() 之前在变量上加 #
    x#.push(5)                // OK
    return 0
}

这是 Toka 属性标记系统(Attribute Token System) 的一个例子——# 后缀表示灵魂的可变性,在声明变量或调用其可变方法时放在变量上。