类用于把一组字段和方法封装成同一种对象结构。字段保存实例状态,方法描述实例行为,方法内部使用 this 访问当前实例。
BT 的类语法保持 JS 风格,但构造实例使用 类名::构造方法(...)。最常用的构造方法名是 new,所以通常写成 User::new(...)。
class 类名 { 字段名: 初始值 字段名 pub 公共字段: 初始值 方法名(参数1, 参数2) { 方法体 } pub 公共方法名(参数) { 方法体 } new(参数) { 初始化逻辑 this } }
对象 = 类名::new(参数) 对象 = 类名::其他公共构造方法(参数)
Class::new() 是 BT 当前的实例化写法,不是 new Class()。
类成员分为字段和方法。
字段使用 名称: 表达式 声明:
class User { name: '未命名' age: 0 }
字段也可以只写名称,不写 : 和初始值,这种写法叫裸字段。裸字段会提前在实例里占一个成员名,默认值是 empty。
class User { name new(name) { this.name = name this } pub get_name() { this.name } } user = User::new('Tom') println user.get_name()
裸字段 name 和 name: '' 不一样:name 的默认值是 empty,name: '' 的默认值是空字符串。构造方法里通常用 this.name = name 覆盖默认值。
方法不需要写 fn,直接写 方法名(参数) { ... }:
class User { name: 'BT' pub get_name() { this.name } }
方法和普通函数一样有返回值。没有显式 return 时,方法体最后一条语句的值就是返回值。
this 表示当前正在操作的实例,只在类方法和构造方法里使用。
class Counter { value: 0 pub inc() { this.value = this.value + 1 this } pub get() { this.value } } counter = Counter::new() counter.inc().inc() println counter.get()
this.value 用来读取当前实例字段,this.value = 1 用来写入当前实例字段,this.method() 用来调用当前实例的其他方法。
访问私有成员时必须直接通过 this.xxx。不要把 this 先赋给别的变量再访问私有成员,因为权限判断只把直接来自 this 的访问视为类内部访问。
class User { password: '' new(password) { this.password = password this } check(password) { this.password == password } pub login(password) { this.check(password) } }
new 是最常用的构造方法名。创建实例时写 类名::new(...)。
class User { name: '' age: 0 new(name, age) { this.name = name this.age = age this } pub info() { this.name + ':' + this.age } } user = User::new('Tom', 18) println user.info()
如果类里没有定义 new,Class::new() 仍然会创建一个实例,并使用类字段里的默认值:
class Config { pub host: '127.0.0.1' pub port: 8080 } config = Config::new() println config.host println config.port
构造方法返回规则需要特别注意:BT 方法默认返回最后一条语句的值。构造方法执行后,如果返回 empty 或 null,Class::new() 会返回新实例;如果返回其他值,就会返回那个值。
因此构造方法里最后一行建议写 this,明确返回当前实例:
class User { name: '' new(name) { this.name = name this } }
不要只把赋值语句放在构造方法最后一行:
class User { name: '' new(name) { this.name = name } } user = User::new('Tom')
上面这个 new 的最后一条语句是赋值表达式,赋值表达式返回右侧的 'Tom',所以 User::new('Tom') 返回的是字符串,不是实例。
BT 的构造入口不固定为 new。任何公开方法都可以用 类名::方法名(...) 作为构造入口:运行时会先创建实例,再把 this 绑定到这个实例执行指定方法。
class User { name: '' role: 'user' new(name) { this.name = name this } pub admin(name) { this.name = name this.role = 'admin' this } pub label() { this.name + ':' + this.role } } tom = User::new('Tom') root = User::admin('Root') println tom.label() println root.label()
除 new 以外,作为构造入口的方法需要是 pub,否则类外不能访问。
类成员默认是私有成员。只有加了 pub 的字段或方法,才能在类外部通过实例访问。
class Account { balance: 0 new(balance) { this.balance = balance this } pub deposit(amount) { this.balance = this.balance + amount this } pub get_balance() { this.balance } can_withdraw(amount) { this.balance >= amount } pub withdraw(amount) { if this.can_withdraw(amount) { this.balance = this.balance - amount true } else { false } } } account = Account::new(100) account.deposit(50) println account.get_balance() println account.withdraw(80) println account.get_balance()
外部可以访问:
account.deposit(50) account.get_balance()
外部不能访问:
account.balance account.can_withdraw(10)
私有成员仍然可以在类内部通过 this 访问:
this.balance this.can_withdraw(10)
BT 当前没有 private 关键字。默认就是私有,需要公开时才写 pub。
公共字段可以在类外部读写:
class User { pub name: '' } user = User::new() user.name = 'Tom' println user.name
私有字段只能在类内部通过 this 写入:
class User { name: '' pub set_name(name) { this.name = name this } pub get_name() { this.name } }
如果在 this 上新增一个类定义里没有声明过的字段,这个字段会作为私有字段保存;如果在外部实例上新增字段,这个字段会作为公共字段保存。
class User { pub set_token(token) { this.token = token this } } user = User::new() user.set_token('abc') user.nickname = 'Tom'
上面的 token 是类内部通过 this 新增的私有字段,nickname 是外部新增的公共字段。
BT 支持链式调用。类方法如果要继续链式调用,返回 this 即可。
class Query { table: '' where_sql: '' limit_size: 0 new(table) { this.table = table this } pub where(sql) { this.where_sql = sql this } pub limit(size) { this.limit_size = size this } pub sql() { 'select * from ' + this.table + ' where ' + this.where_sql + ' limit ' + this.limit_size } } sql = Query::new('users') .where('age >= 18') .limit(10) .sql() println sql
类本身没有调用参数。参数写在构造方法或普通方法上。
class Page { page: 1 size: 20 new(page = 1, size = 20) { this.page = page this.size = size this } } p1 = Page::new() p2 = Page::new(2, 50)
class Name { ... } 会创建一个类值,并把它保存到类名变量中。
Name::new(...) 默认返回类实例。
Name::method(...) 会先创建类实例,再执行指定方法作为构造入口。
return 强制返回。
empty 或 null 时,构造调用返回新实例;返回其他值时,构造调用返回该值。
class User { name: '' password: '' pub role: 'user' new(name, password) { this.name = name this.password = password this } pub admin(name, password) { this.name = name this.password = password this.role = 'admin' this } pub get_name() { this.name } pub rename(name) { this.name = name this } check_password(password) { this.password == password } pub login(password) { this.check_password(password) } pub label() { this.name + '[' + this.role + ']' } } user = User::new('Tom', '123456') admin = User::admin('Root', 'root_pwd') println user.rename('Tommy').label() println user.login('123456') println admin.label()
class Counter { value: 0 new(start = 0) { this.value = start this } pub inc() { this.value = this.value + 1 this } pub dec() { this.value = this.value - 1 this } pub get() { this.value } } counter = Counter::new(10) counter.inc().inc().dec() println counter.get()
Class::new() 是实例化语法;不要写 new Class()。
new 是推荐的构造方法名;如果没有定义 new,Class::new() 也会返回带默认字段的实例。
this,避免最后一条赋值语句把字符串、数字等普通值当作构造结果返回。
pub。
this.xxx 在类内部访问。
private、extends、super、static 语法;不要按 JS 类继承写法使用。
new 中用 this.xxx = [] 或 this.xxx = {} 初始化,避免多个实例共享同一个默认引用。