# 核心语法 每个片段都链接到随 skill 提供、经过检查的完整源码。先看它所属的角色和调用链,再复用到项目;不要把片段单独当作完整 HTTP 项目。 ## 类型和函数 源码:[模板 App](../assets/template/module/hello/greeting/app.dever) ```dever greet(name: Text) (message: Text) { message = "Hello, " + name } ``` 函数写成 `name(输入) (命名输出) { 语句 }`,不写 function/return,调用按位置传参。没有输入或输出时也要保留 `()`。一个输出直接得到值;多个输出按名字访问。 App 的参数、返回值和向外传播的错误都属于公开接口,不能暴露 Domain/Adapter 私有类型。 函数命名表达业务行为,调用路径不附加主题文件名。相关函数、类型和同名分句可以同处一个内聚文件;拆分与复用的判断见 [文件与函数组织](development.md#文件与函数组织),不按函数长度自动增加 helper。 常用类型:`Bool`、`Int`(检查溢出)、`Float`、精确 `Decimal`、`Text`、`Bytes`、`Uuid`、`Id`、`DateTime`、`Date`、`Time`、`Duration`、`Secret`、`Json`。可空用 `T?`,集合用 `List`、`Map`。Model ID 是每个 Model 独有的名义类型,不等于任意 Int。不得把不同表的 ID 混用。 record 用字段初始化;choice 用分支构造。以下 State、label、display 和 grade 位于同一份语法测试,测试入口覆盖每个分句;实际业务无需创建这些演示函数。 源码:[分句测试](../assets/examples/collections/test/content/article/clauses.dever) ```dever type State { Draft Published Rejected(reason: Text) } ``` 源码:[分句测试](../assets/examples/collections/test/content/article/clauses.dever) ```dever label(state: State.Published) (text: Text) { text = "published" } label(state: State.Rejected(reason)) (text: Text) { text = reason } label(state: other) (text: Text) { text = "draft" } ``` ## 分支与边界 用同名函数的不同分句表达条件,不写 if/else/switch/match、条件表达式或递归。这些分句要连续,参数数量和输出声明一致。 每种输入必须恰好匹配一个分句:不能漏掉,也不能重叠;写在前面不会优先匹配。`other` 表示该参数位置没有被其他明确模式覆盖的值。 源码:[分句测试](../assets/examples/collections/test/content/article/clauses.dever) ```dever display(value: Text) (text: Text) { text = value } display(value: null) (text: Text) { text = "missing" } grade(score: Int < 60) (text: Text) { text = "fail" } grade(score: Int >= 60) (text: Text) { text = "pass" } ``` 支持完整类型、choice 分支、null、Bool/Text/数值字面量、Int/Decimal 范围与 other 模式;多输入检查全部输入组合。任一函数都必须为命名输出赋值。不要写 `return` 提前退出,按分句表示结果与失败。 字面量分句适合明确的状态和规则,不意味着可以按某个用户 ID、租户名字或样例数据写业务特例。运行时配置与可信身份的归属见 [配置与硬编码](development.md#配置与硬编码)。 ## 集合与处理函数 Dever 用 `each` 同时表达映射和遍历,没有独立的 `map`:处理函数有一个输出时生成 List,没有输出时逐项执行动作。`filter` 按 Bool 输出筛选,`reduce` 按初始值逐项累积。它们是语言核心操作,不需要导入集合库。 下面的 App 选出已发布且标题非空的文章,整理标题并统计总字数。输入、结果类型与完整调用链都在 [集合项目](../assets/examples/collections/) 内。 源码:[文章 App](../assets/examples/collections/module/content/article/app.dever) ```dever type Article { title: Text published: Bool } type Summary { titles: List title_length: Int } summarize(articles: List
) (summary: Summary) { published = filter(domain.is_published, articles) titles = each(domain.published_title, published) summary = Summary { titles = titles title_length = reduce(domain.add_title_length, titles, 0) } } ``` 处理函数直接使用有业务含义的命名函数。参数顺序、类型和输出由编译器检查,不使用 lambda 或运行期闭包: 源码:[文章 Domain](../assets/examples/collections/module/content/article/domain.dever) ```dever is_published(article: app.Article) (selected: Bool) pure { selected = article.published and text.trim(article.title) != "" } published_title(article: app.Article) (title: Text) pure { title = text.trim(article.title) } add_title_length(title: Text, total: Int) (next: Int) pure { next = total + length(title) } ``` `filter` 的处理函数接收一个元素,输出 Bool;`each` 的单输出成为新 List 的元素;`reduce` 按“元素、当前累计值”传参,输出下一个累计值。顺序保持不变,空集合的 reduce 返回初始值。本例初始值为 0。 集合项目的 [summary 测试](../assets/examples/collections/test/content/article/summary.dever) 用 `each(assert_clean_title, actual.titles)` 逐条断言。这个处理函数没有输出,所以该调用没有返回 List。测试还验证筛选顺序、清理结果、总字数和空集合。 ## 失败和能力 业务错误通过 choice 的 `error` 分支声明,`fail` 传播,`result(call)` 显式捕获;普通调用直接得到成功值。不能用字符串/任意 JSON 代替类型化失败,不能捕获后悄悄吞掉错误。错误映射到 HTTP 的方式见 application.md。 Domain 的纯计算函数可以声明 `pure`,它调用的方法也要满足纯计算要求。Model 的 REST 字段转换只能调用合规的同领域 pure Domain。文件、网络等外部操作经 Port/Adapter,不直接放进普通 App 或 Domain。 不需要写 async/await,普通调用依次完成。要并发执行时用 `run` 启动子任务,再用 `wait/stop` 收尾;不能把任务留到当前作用域之外。 Group/Channel/Stream 的使用范围由编译器检查,不能跨等待、线程或请求随意保存句柄。`result` 只负责捕获结果,不改变调度,也不让原本禁止的操作变成合法。 `Secret` 不可打印、比较或转为普通 Text。密码使用现有 crypto 能力,不自制哈希。类型、分句或调用能力报错时修正真实问题,不增加中转函数、通用包装或吞错分句来绕过检查。 更多完整语法以官方核心仓库同版本 `LANGUAGE.md` 为准;新建项目先使用本 skill 的已验证模板。