语言特性
Hew 为弹性、高性能服务而构建。本页区分当前 v0.9.3 的特性集和更广阔的语言方向。
Actor 模型
聊天室示例由一个 actor 保存成员数和消息数。只有它的 receive 方法能修改这些状态,每次调用都返回带类型的结果。
actor ChatRoom {
var members: i64 = 0;
var message_count: i64 = 0;
receive fn join(user_id: i64) -> i64 {
members = members + 1;
members
}
receive fn post_message(content: string) -> i64 {
message_count = message_count + 1;
message_count
}
}内存模型
普通 owned values 会被递归释放。仿射资源只保留一份清理责任:#[resource] 在离开作用域时安全清理,而 #[linear] 要求每条路径都执行显式的消费操作。
监督树
示例在一个 one_for_one supervisor 下声明三个子项,设置每分钟五次的重启预算,并为每个子项指定 permanent 或 transient 策略。
// A supervisor declares its restart strategy, its restart budget
// (`intensity: N within <window>`), and its children. Each child names the
// actor type and its init args; a per-child `restart:` policy decides whether
// a crash is restarted (permanent), restarted only on failure (transient),
// or never (temporary).
actor DatabasePool {
let pool_size: i64;
receive fn query() -> i64 {
pool_size
}
}
actor CacheLayer {
let capacity: i64;
receive fn get() -> i64 {
capacity
}
}
actor ApiHandler {
let port: i64;
receive fn handle() {}
}
supervisor ServiceCluster {
strategy: one_for_one;
intensity: 5 within 60s;
child db: DatabasePool { pool_size: 16 } restart: permanent;
child cache: CacheLayer { capacity: 1024 } restart: permanent;
child api: ApiHandler { port: 8080 } restart: transient;
}结构化并发
批处理用fork启动三个独立任务,再用await收集结果。scope会等待子任务完成后再返回。
// Structured concurrency: a `scope` block opens a region that joins all
// child work before it returns. Start independent jobs with `fork`, then
// collect each result with `await`.
fn process_batch(a: i64, b: i64, c: i64) -> i64 {
var total = 0;
scope {
let ra = fork run_job(a);
let rb = fork run_job(b);
let rc = fork run_job(c);
let first = await ra;
let second = await rb;
let third = await rc;
total = first + second + third;
};
total
}
fn run_job(job: i64) -> i64 {
job * 2
}并发模式
示例用 select 和 after 超时让两个 actor 调用竞争,随后用 await fork (...) 启动两个独立调用并收集两份回复。
actor Fetcher {
receive fn fetch(key: i64) -> i64 {
key
}
}
actor Store {
receive fn get_users() -> i64 {
0
}
receive fn get_posts() -> i64 {
0
}
}
// Wait for the first responder, with a timeout fallback. Each arm races an
// actor ask; the first to reply wins and the rest are cancelled.
fn race_fetch(primary: Fetcher, fallback: Fetcher, key: i64) -> i64 {
select {
resp from primary.fetch(key) => resp handle e { -1 },
resp from fallback.fetch(key) => resp handle e { -1 },
after 500ms => -1,
}
}
// Run independent calls concurrently and collect every result.
fn parallel_fetch(db: Store) -> (i64, i64) {
let (users, posts) = await fork (db.get_users(), db.get_posts());
(users.expect("store stopped"), posts.expect("store stopped"))
}
fn main() {
let primary = spawn Fetcher;
let fallback = spawn Fetcher;
println(race_fetch(primary, fallback, 42));
let db = spawn Store;
let (users, posts) = parallel_fetch(db);
println(f"{users} {posts}");
}状态机
连接状态机在一张表中声明事件、状态、带 guard 的转换和默认行为。step 只应用为当前状态和事件声明的转换。
// A connection lifecycle as a compiler-checked state machine.
// Events are declared up front; transitions route with `=>` and a body
// that constructs the target state. Every (state, event) pair must be
// covered — `default { state }` makes the rest a no-op stay.
machine Connection {
events {
Connect { host: string; }
Disconnect;
HeartbeatTimeout;
}
state Idle;
state Connecting { host: string; }
state Connected { host: string; }
state Disconnected { retries: i64; }
on Connect { host }: Idle => Connecting { host: host }
on Connect { host }: Disconnected => Connecting when state.retries < 5 { host: host }
on Disconnect: Connected => Disconnected { retries: 0 }
on HeartbeatTimeout: Connected => Disconnected { retries: 0 }
default { state }
}
fn main() {
var conn = Connection.Idle;
_ = conn.step(Connection.Event.Connect { host: "10.0.0.1" });
println(conn.state_name()); // Connecting
}对失败进行类型化的 Actor 调用
这个本地 actor 示例展示了对失败进行类型化的调用边界:每个请求都返回由调用方处理或传播的结果。
// Actor calls make failure part of the method surface. Every call yields a
// Result, so callers handle a stopped actor or expired request deadline alongside
// the successful value. The error branch below has the typed
// ActorError<Never, Never> carried by this method.
actor Worker {
let id: i64;
receive fn process(task: i64) -> i64 {
task + id
}
}
fn dispatch(task: i64) -> i64 fails ActorError<Never, Never> {
let w = spawn Worker { id: 1 };
// `?` on the binding unwraps Ok and propagates a typed ActorError<Never, Never>
// on the failure branch.
let answer = (w.process(task))?;
answer
}
fn main() {
match dispatch(7) {
.Ok(v) => println(f"result = {v}"),
.Err(_) => println("dispatch failed"),
}
}Wire 契约
配置文件 schema 为每个字段分配稳定的数字标签。旧或新的对端可以省略可选的 verified 字段,而兼容性检查器会跟踪标签变化。
// Wire types carry explicit field tags (@1, @2, ...) for forward- and
// backward-compatible binary encoding. Optional fields may be omitted by
// older or newer peers without breaking the schema.
#[wire]
type UserProfile {
name: string @1;
email: string @2;
age: i32 @3;
verified: Option<bool> @4 optional;
}类型系统
Hew 的类型系统围绕 actor 隔离和 capability 检查边界构建。编译器在编译时强制执行 Send/Frozen 检查、穷尽性和 actor 隔离。
通过 monomorphization 实现泛型
编译器会针对程序使用的每个具体类型,专门化泛型类型和函数。
Send + Frozen 能力 traits
Send 标记可以跨越 actor 边界的值。Frozen 标记可安全共享的深度不可变值。
双向类型推断
预期类型会流向 lambdas 和泛型调用,在减少注解的同时让推断类型对检查器可见。
带穷尽性的模式匹配
Match 表达式会在编译期检查完整性。编译器确保每一种可能情况都被处理。
使用 extern blocks 的 C FFI
Extern blocks 描述 C symbols 及其 Hew signatures。FFI 默认是 unsafe;ABI、指针和生命周期的正确性仍由调用方负责。
Option<T> 和 Result<T, E>
缺失和可恢复失败都表示为显式值,通过模式匹配处理或用 ? 传播。
带 adapters 的 Iterator trait
map、filter、fold 等 adapters 在序列上组合惰性变换。
编译
Hew 今天可以编译为原生机器码。hew build 命令驱动 Rust frontend 和 Rust LLVM backend,每个阶段都会保留更多 checker 保证。