2409dip草稿,和类型
原文
D按构造和型.
理由
在语言
中添加和
类型提供了三个关键的可用性优势
.
1,业务
逻辑数据的快速原型设计
.可与元组结合
使用,只需要一个声明
,就可完整构造
表示网络
形式的数据.
2,启用基于栈的异常机制
,而不用运行时展开库
.这有可能实现单步指令
一样便宜的抛.同时保证在抛它的位置附近
抓抛的每个异常
.不用堆分配
.
3,与匹配
相结合的安全性,保证了在编译时不会滥用@safe
,从而破坏程序
.
先前的工作
以前在D中实现的库类型
,这些可分为两类
.
1,不支持元素名:
std.variant
代数
std.sum
类型
2,约束集
中,(可选)支持非唯一类型的元素名
:
taggedalgebraic
该高度强调
仅针对库实现
的更简单元素类型
的划分
,在其他语言
中也可见:
C++
变量
语言支持
可分为三类
,而不是两类:
1,不支持
元素名:
TypeScript
(类型脚本)
2,可选元素名
:
rust
.
3,可选元素类型
:
SML
OCaml
描述
和类型
是一个只能存储一个值
,且访问和更改
受联集
约束的容器
.由提供标签联行为
的标签
提供保护权限
.
sumtype Identifier = int | :None | string text;
约束
有三个形式.
1,整
类型.
2,按typeof(:None)
类型覆盖:None
符号的成员
.
3,有叫text
名的串
类型.
必须
至少有一个约束.
如果只有一个约束
,则按元素的别名 本
对待它.为它提供隐式安全访问和变更
.
sumtype Int = int;
Int i = 2;
i *= 5;
赋值
与结构
类似,赋值一个和类型
给另一个和类型
.
析构目标
,然后复制源到该目标
,复制后更新标签
,复制构造器和析构器
.
sumtype S = int | bool;
S source, target;
//target.destroy;
target = source;
// target.__tag = source.__tag;
// target.__copyctor = source.__copyctor;
// target.__dtor = source.__dtor;
赋值用户
未显式请求的元素
稍微复杂
一些.仅根据约束集
检查是不够的,必须考虑和类型
变量自身.
sumtype S1 = int;
sumtype S2 = int | bool;
S1 source;
S2 target;
target = source;
和类型
类型优先于约束集
中的元素
.如果需要保证
它设置的是元素
,而不是和类型
变量,请使用cast
.
访问元素
要访问
按类型的和类型
元素的值,请使用转换
.
sumtype S = int | bool;
S s;
s = 5;
assert(cast(int)s == 5);
如果要按名访问元素
,请为其提供memberof(的成员)
符号.
sumtype S = int i | bool;
S s;
cast(:i)s = 2;
assert(cast(:i)s == 2);
这与和类型
的声明中可见的重写
相同.按typeof(:Identifier)
重写符号
的成员.在集合
中提供唯一元素
.
在元素
中存储值
总是是安全
的.它在复制前析构容器
.
如果不匹配
,从元素
中取值
是不安全
的.要访问元素
值,这是@系统
级的.
属性
和类型
有以下成员
:
1,__tag
,一个指示设置了哪个元素
的整数标签值
.
2,__tagTypes
,取约束集中的类型
.
3,__tagNames
,取约束集中每个元素名
,如果没有,则序列中的串
将为无效
.
4,__tagValues
,约束集中,对元素描述
,把偏移
映射到其标签
值.
按标签类型的哈希值
组合标签名
,来定义标签值
.属于size_t
类型.这样可增加和缩小约束集
,这样,无需完全匹配和再赋值标签值
.这对某些用例
(如值类型异常
)非常重要.
第一个元素
是选择
的默认标签
.在下例中:None
是.init
要用的默认元素
.
sumtype S = :None | int;
类型限定符
对和类型
,应用类型限定符
时,也针对约束集
.
sumtype S = int* | bool;
const(S) s;
pragma(msg, S.__tagTypes[0]); //const(int*)
布局
和类型
基于结构,与结构
一样,它会自动调用
其复制构造器/析构器
.根据约束集
,它有以下可变大小的布局
:
1,标签值
2,复制构造器指针
3,析构器指针
4,标签值
如果约束集
中元素
不需要它,则可省略它
.如果约束集
中的所有元素的大小
都为零,则可省略
.
如果需要,编译器应生成一个取标签值的指针
的补丁
函数,复制它,并与构造器/析构器
组合在一起,并按闭包
转换它.但是,它应该可在没有新函数
时重建闭包
.
复制构造器
代替后复制
.但是,它可能需要生成包装器函数
.
布局大小
必须是可变
的,以允许它是可保存在寄存器
中的单个机器字
的大小.这允许其他语言元素
如值类型异常
,来保持零成本
的能力.
如果布局
中有复制构造器或析构器
,则无论选择哪个元素
,它都必须为非无效
.
对其他元素
要用的未用内存
将为未定义
状态,且访问
它不安全.
WalterBright
在DConf2024
时记住的一个优化策略
是利用进位标志
来指示有错误
.
在返回非空
的和类型
时,只要和类型
元素仅包含成员符号
且返回类型
适合寄存器
,这允许省略标签
.
匹配
可查看DIP1048
提供的匹配
,以理解
提供它使用的属性
的和类型
.注意,缺少一个__tagValue
,编译器了解从何处及如何取此引用
.因此不应存在它
.
sumtype S = int | string text | :None;
S s;
s.match {(:text someTextVar) {};(int) {};(:None) {};
};
匹配模式
现在支持使用的成员
符号来代替类型
.它在约束集
中查找给定元素名
,或转换
为typeof(:Identifier
)类型并匹配
.
通过在编译时可访问的__tagNames
串序列中查找索引
,扩展此功能
到和类型
库.
也是按引用
,访问元素值
是个@safe
操作.它没有按转换
访问的限制
.
最后,匹配
式支持返回值
.返回的值
将是语言和类型
.每个中
可能有在结果类型
中包含
的不同类型
.
sumtype S = :None | int;
sumtype S2 = int | bool;
S1 s1;
S2 s2 = s1.match {(:None) {if (random() > 0.5)return true;elsereturn 2;};(int v) {return v;};
};
语法
注意,可模板化它
,当用的成员符号
来提供元素
时,它会按一个语义表示的概念
重写为统一语法
.
+ SumTypeDeclaration:
+ sumtype Identifier SumTypeConstraints
+ sumtype Identifier TemplateParameters Constraint|opt SumTypeConstraints
+ SumTypeConstraints:
+ SumTypeConstraint , SumTypeConstraints
+ SumTypeConstraint
+ SumTypeConstraint:
+ MemberOfOperator
+ Type Identifier|opt
MatchPattern:
+ MemberOfOperator FunctionLiteralBody
ParameterDeclaration:
+ ParameterAttributes|opt MemberOfOperator Identifier
TypeSpecialization:
+ sumtype
重大更改和弃用
名为和类型
的符号都可能破坏.可能方法
是要求关键字
仅在一组版本
及更高版本
中识别它
.