31用d编程属性合同编程
可以指定成员函数
作为属性名.
这样a.b
,b就可能是函数,只要前面加了@属性
.
.length
属性不能修改静态数组.对切片,有可能会分配空间,甚至移动到新位置+初化新成员.
因为属性,所以调用函数,可以不加()
.
struct Rectangle {
double width;
double height;
}
auto garden = Rectangle(10, 20);
writeln(garden.area);
struct Rectangle {
double width;
double height;
double area() const @property {
return width * height;
}//常,保证本函数不修改本对象
}
这样,就强制保证了一致性
.不会被修改.
auto garden = Rectangle(10, 20);
writeln("面积为: ", garden.area);
就像第三个成员变量一样使用.
void area(double newArea) @property {
auto scale = sqrt(newArea / area);
width *= scale;
height *= scale;
}
修改,作为set
.
当然.也能够实现成员函数的只读访问,即用个函数包装成员.不允许设置(即写)
in,out
用于保证函数的不变.而类/构
则:
class School {
private:
Student[] students;
size_t femaleCount,maleCount;
invariant() {//用这个不变量来保证
assert(students.length == (femaleCount + maleCount));
}
// ...
}
可在构
中定义.可以有多个invariant()
块.
可在构造器后,析构器前
,及在执行公有/导出成员函数前后
,导出函数是导出在动态库接口
中的函数.
dmd deneme.d -w -release
,发布时依然禁用了.发布太厉害了.
接口和类
成员也可有in/out
,允许为他们定义基本的限制(前条件)
或者为用户定义后条件
继承类可在覆盖的函数中
定义进一步的in/out
,可松可严格.只要有一个满足相应的限制块
就行了.
in
块只相应的满足就行.即进块可以变松,只要不出现断定错误就可
.如果父级失败,就执行子级进块
,相当于||…||…
out
块所有限制都要满足.则是(…&&…)
执行函数时in
/out
从最上到下一层层检查.
interface Iface {
int[] func(int[] a, int[] b)
in {
writeln("Iface.func.in");
assert(a.length == b.length);
} out (result) {
writeln("Iface.func.out");
assert((result.length % 2) == 0);
}
}
class Class : Iface {
int[] func(int[] a, int[] b)
in {//放松了.
writeln("Class.func.in");
assert((a.length == b.length) ||
(a.length == 0) ||
(b.length == 0));
} out (result) {
writeln("Class.func.out");
assert((result.length != 0) &&
(result[0] == result[$ - 1]));
} body {//示例块
writeln("Class.func.body");
int[] result;
if (a.length == 0) {a = b;}
if (b.length == 0) {b = a;}
foreach (i; 0 .. a.length) {
result ~= a[i];result ~= b[i];
}
result[0] = result[$ - 1] = 42;
return result;
}
}
import std.stdio;
void main() {
auto c = new Class();
writeln(c.func([1, 2, 3], []));
}
示例:
class Protocol {
void compute(double d)
in {
assert(d > 42);
} body {
// ...
}
}
class SpecialProtocol : Protocol {
/* Because it does not have an 'in' block, this function
* effectively disables the preconditions of
* 'Protocol.compute', perhaps unintentionally. */
override void compute(double d) {
// ...
}
}
void main() {
auto s = new SpecialProtocol();
s.compute(10); /* BUG: Although the value 10 does not
* satisfy the precondition of the
* superclass, this call succeeds. */
}
子块,不检查in
块,结果出错.按道理子块
也要继承父块
的前提条件.
class SpecialProtocol : Protocol {
override void compute(double d)
in {
assert(false);//加个永远假.
} body {
// ...
}
}
加个假这样,防止不检查.因为进
条件是||...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现