d可变存储类
引入了一个可应用于聚集字段的新__mutable
存储类
__mutable
存储类修改字段
上类型限定符
的传递性
.
只能在@system
上操作__mutable
数据,且只能在私
成员上应用__mutable
.
struct S{
int* p;
shared int* s;
private __mutable{
int* m;
shared int* ms;
}
//private __mutable const int* mc;
//错误:不能同时是__mutable和const
//private __mutable 不变 int* imc;
//错误:不能同时是__mutable和不变
//__mutable int* pm;
//错误:`__mutable`字段必须是`private`
}
struct T{
private __mutable int* a;
private{
__mutable int* b;
}
__mutable{
private int* c;
}
}
static assert(!__traits(isUnderUnderMutable, S.p));
static assert(__traits(isUnderUnderMutable, S.m));
//__mutable int x = 2;
//错误:`全局变量和静态变量`不能是`__mutable`
/+int* bar()@safe{
S s;
return s.m;
//错误:在`@safe`的`bar`函数中无法访问`__mutable`的`m`字段.
}
+/
void foo(inout(int)*)@safe{
// __mutable int* p;
//错误:__mutable只能应用于聚集类型的字段
S s;
const(S) cs;
不变(S) is_;
shared(S) ss;
shared(const(S)) css;
inout(S) ws;
const(inout(S)) cws;
shared(inout(S)) sws;
shared(const(inout(S))) scws;
//对非`__mutable`字段,传播限定符(现有行为)
static assert(is(typeof(s.p)==int*));
static assert(is(typeof(cs.p)==const(int*)));
static assert(is(typeof(is_.p)==不变(int*)));
static assert(is(typeof(ss.p)==shared(int*)));
static assert(is(typeof(css.p)==shared(const(int*))));
static assert(is(typeof(ws.p)==inout(int*)));
static assert(is(typeof(cws.p)==const(inout(int*))));
static assert(is(typeof(sws.p)==shared(inout(int*))));
static assert(is(typeof(scws.p)==shared(const(inout(int*)))));
static assert(is(typeof(s.s)==shared(int*)));
static assert(is(typeof(cs.s)==shared(const(int*))));
static assert(is(typeof(is_.s)==不变(int*)));
static assert(is(typeof(ss.s)==shared(int*)));
static assert(is(typeof(css.s)==shared(const(int*))));
static assert(is(typeof(ws.s)==shared(inout(int*))));
static assert(is(typeof(cws.s)==shared(const(inout(int*)))));
static assert(is(typeof(sws.s)==shared(inout(int*))));
static assert(is(typeof(scws.s)==shared(const(inout(int*)))));
//对`__mutable`字段,修改`传播限定符`:
static assert(is(typeof(s.m)==int*));
static assert(is(typeof(cs.m)==int*)); // TODO: good?
// 显式转换为可变或共享
static assert(is(typeof(*cast(int**)&cs.m)));
//允许显式重转
static assert(is(typeof(*cast(shared(int)**)&cs.m)));
//允许显式重转
static assert(is(typeof(is_.m)==shared(int*))); // 不变是隐式共享的
static assert(is(typeof(ss.m)==shared(int*)));
static assert(is(typeof(css.m)==shared(int*)));
static assert(is(typeof(cs.m)==int*));
static assert(is(typeof(ws.m)==int*)); // TODO: good?
static assert(is(typeof(*cast(int**)&ws.m))); // 显式重转
static assert(is(typeof(*cast(shared(int)**)&ws.m))); //显式重转
static assert(is(typeof(cws.m)==int*)); // TODO: good?
static assert(is(typeof(*cast(int**)&cws.m))); // 显式重转
static assert(is(typeof(*cast(shared(int)**)&cws.m))); // 显式重转
static assert(is(typeof(sws.m)==shared(int*)));
static assert(is(typeof(scws.m)==shared(int*)));
static assert(is(typeof(s.ms)==shared(int*)));
static assert(is(typeof(cs.ms)==shared(int*)));
static assert(is(typeof(is_.ms)==shared(int*)));
static assert(is(typeof(ss.ms)==shared(int*)));
static assert(is(typeof(css.ms)==shared(int*)));
static assert(is(typeof(ws.ms)==shared(int*)));
static assert(is(typeof(cws.ms)==shared(int*)));
static assert(is(typeof(sws.ms)==shared(int*)));
static assert(is(typeof(scws.ms)==shared(int*)));
}
即,有__mutable
时,常/不变
就没了传递性
.修改__mutable
是已定义行为.
对无法确定共享
状态(@system
,转为正确共享/不共享
可变类型并修改内存
)的类型
也是如此(已定义行为).
通过转换类型的const/不变
引用的修改
变量,同样是未定义行为
.
同纯互动
即使用__mutable
,也希望得到强保证
,因此应根据转换/规则
来定义pure
和不变
.为了定义规则,为了简单,我用函数调用
,但规则
也适用于语句序列
.按SSA(静单赋值)
想像D程序,无论是否为纯,右侧赋值
是"函数".
(*注意"
:下面想法需要更多工作).
"基本语义
"是省略
了限定符
时D语言的语义
.
这些规则的含义是:
一个不抛
且无未定义行为
程序,但可转换
为可抛
或有未定义行为
程序,则自身有未定义行为
.
用基本语义
触发错误,但可转换
为使用基本语义
不抛错误的程序
具有未定义行为
.
基本规则
使用相同的不变
参数的(返回无间接
的类型)强纯函数时,返回相同结果
.(无论多少中间交互
.)对有间接
的返回类型
,该函数
返回始终具同构可变别名
的数据图
.
从可安全转换强纯函数
返回引用集
为不变/共享
.
可安全地删除结果未用
的强纯
函数.
如果有两个后续pure
函数调用foo(args1...)
,和bar(args2...)
.其中数据可从1参和2参
传递性可达,且仅在常和不变
数据中重叠
(包括通过常和不变
对象的__可变
字段访问数据
),则两个调用
可安全地交换
顺序(当然,仅适用于两个函数都无参数).
强纯
函数总是可与相邻
的不纯
函数交换
顺序.
// 创建1,2参等
auto a = foo(args1...);
auto b = bar(args2...);
//用a和b
和
// 创建1,2参等
auto b = bar(args2...);
auto a = foo(args1...);
//用a和b
总可交换的.
__可变
函数
带有__mutable
注解函数
不受这些
规则的约束.__mutable
函数必须是pure
和@system/@trusted
.调用@system__mutable
函数的@trusted纯
函数必须确保,对pure
调用@trusted
函数,上述规则有效.
重要
:注意,在pure
函数中,即访问
内存地址和不变
数据身份
,必须是非@safe
的.(如is
表达式.)
原理:用__mutable
函数,可在实现抽象
时,方便
地打破规则,最终创建满足规则
的高级抽象.__mutable
函数的一个用例是释放
.
消除公共子式
以下规则启用公共子式消除:
只能从其他__mutable
或pure
析构器中调用__mutable
函数.
(注意,此规则
不必是语言定义
的一部分,因为可能有更宽松
条件使下面规则
起作用,但让类型系统
检查它是有意义
的.)
然后可加以下消除公共子式
规则:
如果有两个
(相同的
)强纯
(非__mutable
)函数调用
auto a = foo(arg);
auto b = foo(arg);
可转换为:
auto a = foo(arg);
auto b = a;
原理:允许消除公共子式
/透明引用
,这是纯
函数的重要属性
.常见消除子式
的主要
问题是:除非全部在析构器中
,释放
可能会棘手.
其他注意事项
不变
隐式为共享
,是个小问题.不变
只有在不能传递性
修改时才有意义.__mutable
打破了该点,因此无安全
方法来支持常
引用的__mutable
.上面方法
本质上要求实现
记录是否共享
了当前对象
.
或可考虑使用单独
的(非共享
的)不变
和共享不变
类型,这样就知道常
内存是非共享
的,而共享 常
内存是共享
的.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现