d的和类型
理由
和类型(sumtype)在许多语言中都是有用和流行的.和类型与证明是有用和流行的模式匹配配合得很好.与C风格的无标签联相反,和类型主要特征是保证安全访问成员.并保证处理和类型的所有情况.Sumtypes是可靠避免常见编程的在不先检查值是否无效下就访问值的错误.当函数需要指示有错误及返回错误无效时,Sumtypes是抛异常的替代方法.
先前工作
std.和类型
同D受限的表现力工作时,它是出色的实现,但因为要用类型来指定和类型的用例,有限制.这里
1,std.和类型不能包含普通枚举成员
2,std.和类型无法优化不存在的标签,如,当有:
enum Option { None, int* Ptr }
3,如果模式匹配中未考虑所有情况,则不会产生编译时错误,而是抛异常
4,无法提取子匹配并赋值给其他变量
5,仅按类型而不是按值匹配
6,整(int)和指针不能同时且安全的在和类型中.
7,不能有属于同一类型的两个字段声明
swift
rust
c++
描述
和类型有一组独特命名成员.任一时候,只能有一个这些成员.由叫标签的隐藏字段指定是哪一个.
和类型具有枚举,构和联的特征.因为可包含一组命名整数值,像枚举.因为它包含一个标签和一个和类型的所有成员的联的两个字段,又像一个构.又因为所有成员共享第二个字段,又像一个联.
和类型大小是:标签大小+最大成员+对齐填充.
字段声明的成员函数受联的成员函数的限制.
和类型的成员可有由实现按顺序赋值的整数值,程序员赋值的唯一整数值,也可是指定类型值.
和类型的第一个成员默认是它的初值.可复制和类型.
和类型的成员不能有复制构造器,后复制(postblit)或析构器.
和类型的枚举成员类型是可表示所有枚举成员值的最小类型.如果没有负值,则用正类型.
和类型特例允许使用非空针.
引入了新QueryExpression式,可查询和类型是否包含指定成员.
语法
SumTypeDeclaration:
`和类型` Identifier SumTypeBody
SumTypeTemplateDeclaration
SumTypeBody:
`{` SumTypeMembers `}`
SumTypeMembers:
SumTypeMembers
SumTypeMember `,`
SumTypeMember `,` SumTypeMembers
SumTypeMember:
EnumMemberAttributes SumTypeMember
EnumMember
FieldDeclaration
EnumMember:
Identifier
Identifier = AssignExpression
FieldDeclaration:
Type Identifier
Type Identifier = AssignExpression
SumTypeTemplateDeclaration:
`和类型` Identifier TemplateParameters Constraint (opt) SumTypeBody
QueryExpression:
`?` PostfixExpression `.` Identifier
替代语法
和类型 Option(T) = None | Some(T);
对比:
和类型 Option(T) { None, Some(T) }
示例
函数可返回两种类型,一种表示错误,另一个是结果.可实现为:
和类型 Result
{
Error,
int Value
}
Result func()
{
Result res; // 初化为Result.Error
if (things went well)
res.Value = 25; // 非错误结果
return res;
}
void plugh()
{
Result ret = func();
if (?ret.Error)
printf("中错误\n");
else
printf("结果是%d\n", ret.Value);
}
如果在Kod中存储整,则只能(通过运行时检查标签)提取整.对整*来说也一样.因此,虽然整和整*占用相同存储空间,但不能混为一谈.Kod的大小会占用2个整,一个是标签,一个是x|y.
enum Kod
{
int x;
int* p;
}
模板
可像构声明一样参数化和类型:
enum Option(T)
{
int Integer,
T Other,
}
查询式
如果和类型包含指定变量,查询式返回真,否则假.
x = Xyzzy.busy;
if (?x.busy)
writeln("busy");
else
writeln("not busy");
安全
想法是避免访问(由标签指定的)不在和类型中值.
写
写入和类型是安全的,因为它会用新值重写现有值.
enum Xyzzy { busy, int allow, int* ptr }
Xyzzy x;
x = Xyzzy.busy; // 好
x = Xyzzy.allow(3); // 好
int i;
x = Xyzzy.ptr(&i); // 好
读
只能读取实际在和类型中的值:
Xyzzy x = Xyzzy.busy;
Xyzzy y = x.busy; // 好
y = x.allow; // 运行时错误
y = ?x.allow ? x.allow : Xyzzy.busy;
x = Xyzzy.allow(3);
y = x.allow; // 好
指针和引用
对调用和类型成员函数,和类型的类型成员的指针和引用是很有用的.会造成以下问题:
int i;
Xyzzy x = Xyzzy.allow(3);
int** p = &x.allow; // 好
x = Xyzzy.busy;
*p = null; // 出错
目前最务实方法是,在@safe中,简单禁止使用和类型成员的地址或引用.
隐式转换和转换
和类型不会与其他类型隐式互转换.
是式(IsExpressions)
使用sumtype关键字扩展是式来标识和类型.
混杂名
添加TypeSubtype.
TypeSubtype:
`No` QualifiedName
非空针特例
可用sumtypes来创建非null指针.如,以下在Null成员和Ptr成员之间共享存储.因此,不检查Null就无法提取Ptr,默认初化指针(Pointer)为Null.
和类型 Pointer
{
Null,
int* Ptr,
}
Pointer nnp; // 默认初化为Pointer.Null
if (?nnp.Null) printf("null pointer\n"); // 好
int* p = nnp.Ptr; // 运行时错误
int i;
nnp.Ptr = &i;
p = nnp.Ptr; // 好
这里问题是:
nnp.Ptr = cast(int*)null;
p = nnp.Ptr; // 编译, 但置p=null
解决方法是识别,是0成员+指针形式.然后,和类型用指针合并标签.因此如果赋值空针给和类型,则和类型用Null打标签.禁止空针的语言不需要该特例.
在DMD中的实现
和类型共享enums,structs,和union的特征.按其中之一的和类型实现可能太复杂,不值得.因此,为它构建新类型和新声明.
但由于可按枚举实现只有枚举成员的和类型,编译器应重写它.同样,只一个字段的和类型声明应按构重写(并省略标签).此外,可按指针重写值为0的枚举成员及1个指针的字段声明的和类型.
匹配模式
适合访问和类型的模式匹配语句是另一个DIP的主题.
未来方向
除了枚举成员和字段声明外,还可添加元组声明.
中断和弃用
已在火卫一中按模块名用和类型.必须:
0,查找其他关键字
1,更改std.sumtype模块名
2,使用环境相关关键字
浙公网安备 33010602011771号