# 7. 资源、类型与类 Endorphin 采用一切皆对象的模型。Object 是类型继承关系的根,Type 是类型对象的实例类型。Object 是 Type 的实例,Type 是自己的实例,并在继承线上继承 Object;Object 没有父类型。数值、文本、图片、代码、函数、类型定义及运行实例都接入这套闭环,平台按类型管理其生命周期。 资源 atom 是对象可独立识别、保存和引用的单元,资源 ID 将这些单元连接成引用图。实例化、继承、成员及代码依赖在图中保存为不同含义的关联。class 与 agent 构造入口自身也是对象,用于组织具体类型及高级结构;workspace 和 namespace 提供资源归属与命名管理。 类型描述资源或值的结构及其允许的用法。类型系统约束字段、变量、容器元素、引用目标和定义资源,并通过明确的能力关系组织 class、Function 和 agent 等高级结构;函数签名也使用这套类型规则。 ## 7.1 类型标注 类型标注采用 `名称: 类型` 的形式: ```text price: Number name: String ``` 本文示例使用: | 类型名 | 表达的值 | | -------- | ------------------------------ | | `Number` | 统一数值,包含整数与小数,不按机器位宽或浮点表示分成语言类型 | | `String` | 文本内容 | | 用户声明的类名 | 属于该声明类型并满足字段约束的数据 | `Number` 是本书采用的统一数值类型名提案,`String` 沿用文本类型名提案。基础资源类别已经确定,完整类型命名、精度和转换规则见[规范状态](../appendices/specification-status.md#基础资源与变量)。`String` 表示文本值,与第 12 章的 Text 界面组件不同。 ### 基础常量资源 基础常量资源的内容不可原地修改。数字和文本可以通过字面量表达,媒体和 GIS 数据由平台接收并转换成类型化资源;它们不要求用户先声明 class。 | 基础类别 | 语言层面的内容 | 平台承担的表示工作 | | --- | --- | --- | | 数值 | 数字及其运算 | 选择可保存该数值的表示,不要求调用者选择 int32、float 等机器类型 | | 文本 | 字符与文本内容 | 保存和提供统一文本值 | | 图片 | 图像内容 | 导入转换、内部标准表示与导出编码 | | 视频 | 随时间变化的影像内容 | 导入转换、内部标准表示与导出编码 | | 音频 | 声音内容 | 导入转换、内部标准表示与导出编码 | | GIS 数据 | 地理空间内容 | 导入转换、统一空间数据表示与导出编码 | 数值表示以可表达和保存为优先目标,平台可以使用大数或其他可扩展表示,接受由此产生的性能成本。`100` 与 `1.5` 都属于统一数值类别,不因是否包含小数点而选择不同的机器类型。大数表示本身不决定除法、舍入或任意实数的精确性,这些算术规则仍需明确。 平台接受的媒体与 GIS 格式在导入后转写为各自的内部标准格式,导出时再编码为受支持的目标格式。业务代码面对图片、视频、音频或 GIS 数据的类型语义,无需为每种输入编码自行解析句柄和 buffer。修改基础内容产生新的内容值;变量可以改为引用新值。 具体标准格式、支持的导入与导出格式,以及转换中的精度、元数据和坐标系统规则另行定义。格式归一化不直接规定所有类别具有同一种文件编码,也不要求源码暴露平台内部的缓冲区。 ### 资源与引用 基础值可以作为表达式结果、函数参数或返回值。变量是一项可改变目标的语言引用,可以指向基础常量资源,也可以指向函数、class 或 agent 定义及其可用实例;引用与实例的具体类型表达仍待定义。 这里的“指向”表达语言语义,不要求开发者处理裸内存地址、手动分配或释放。变量改变引用目标与修改基础常量内容是不同操作,详见[变量与资源引用](08-expressions-and-bindings.md#86-变量与资源引用)。 资源需要独立保存、分享或再次引用时,以独立 ID 识别,由 workspace 管理归属、namespace 提供命名与检索。一个资源可以有多个命名入口;移除入口不清除仍被保留程序引用的资源。具体登记形式与实例标识待定,临时值不因此自动获得永久名称,详见[资源引用](07-top-level-types/references.md)。 ## 7.2 class 声明 代码归属:`atelier:shop.data`。 ```endorphin class Product { name: String price: Number } ``` 该声明定义名为 `Product` 的数据结构,含有两个字段:`name` 为文本,`price` 为数值。使用 Product 数据的代码依据同一结构读取字段,不需要为前端另写一份对应结构。 类名是标识符。本文最小示例展示字段声明,每个字段写出名称和类型,字段之间不使用逗号或分号。class 也可以组织成员函数;函数作为成员时需要类内作用域和实例关联规则,具体形式见[规范状态](../appendices/specification-status.md#声明与类型)。 ## 7.3 类型与值 `Product` 表示一个声明的类型;具有 Product 类型并满足其字段约束的值,才包含本次业务数据。仅有相同字段不自动使其他类型的值成为 Product。 Product 类型对象是 Type 的实例,商品对象是 Product 的实例;Product 在继承线上以 Object 为基础。引用 Product 不创建商品对象,商品与类型定义也不共享同一个资源身份。字段内容可以继续引用其他对象,其保留关系按对象图处理。 类声明本身不取得某件商品,也不指定数据库、表或连接。通过类型取得数据的用法在[数据读取](10-data-access.md)中说明;构造、方法与默认值属于独立的类型规则。 ## 7.4 字段访问 函数体片段;局部名称 `product` 表示已取得的 Product 值: ```endorphin let name = product.name let price = product.price ``` 成员访问使用点号。第一行取得文本字段,第二行取得数值字段。字段使用的类型由声明决定;读取不存在的字段不是有效的 Product 用法。 成员访问和 let 的表达式规则见下一章。 ## 7.5 类型检查与共享 Preflight 理解类和字段声明,检查字段访问、函数参数与返回值的类型关系。inflight 中取得和使用的数据必须符合对应类型及字段约束。 跨 namespace 引用类时,引用的是定义该结构的声明,不改变调用方代码的归属。声明是否可访问取决于可见性和权限规则,见[程序结构与导入](04-program-structure.md)。 ## 7.6 类型身份与兼容 Endorphin 不采用仅依据成员结构判断兼容的结构类型规则。用户声明的类型按其声明身份区分;字段或方法相同,不自动建立类型兼容或能力实现关系。 类型声明可以通过 namespace 与声明名查找,绑定后的引用指向声明资源的独立身份。引用同一个声明不创建新类型;不同声明不能仅凭名称或成员相同被认定为同一类型。 代码归属:`atelier:shop.data`。沿用本章 Product 声明,并增加以下类声明: ```endorphin class ListedProduct { name: String price: Number } ``` Product 与 ListedProduct 都有 name 和 price,但它们是不同的类型。本例没有建立继承、转换或其他兼容关系,因此 ListedProduct 值不能自动作为 Product 参数使用。 ```text Product 值 → 接收 Product 的参数:类型符合要求 ListedProduct 值 → 接收 Product 的参数:不能仅凭字段相同通过检查 ``` 构造某个声明类型的值时仍须检查字段及其类型;这类检查不等于允许不同类型按结构互换。类型推断也不要求结构兼容,具体推断规则仍待定义。 类型可以显式组合多个 trait 能力,不要求单一的树形继承结构;具体声明、实现及转换规则仍需评审。候选代码见[Type、Trait、Code、class](07-top-level-types/definitions.md),确定程度见[规范状态](../appendices/specification-status.md#声明与类型)。 Object 的共同基础允许以统一的对象位置保存不同具体类型,但不会消除具体名义身份。以 Object 持有 Product 对象,不能据此将它当作 ListedProduct 使用;数值、调用等专门操作仍依赖相应类型或显式能力。 [上一章:词法结构](06-lexical-structure.md) · [继续第 7 章:类型系统](07-top-level-types/README.md) · [下一章:表达式与绑定](08-expressions-and-bindings.md) · [目录](../README.md)