d的隐藏类型
原文
首先,介绍一下背景.
D中的输入区间是带front,popFront,empty成员的类型:
它构成了迭代的基础.只是为了好玩,设计一个返回永久随机数序列的输入区间.也叫生成器.
如下(不是很好的随机数生成器,但暂时可以):
module rnd;
struct RandomNumberGenerator {
this(uint seed) {
next = seed;
popFront(); // 让他跑
}
@property int front() {
return ((next / 0x10000) * next) >> 16;
}
void popFront() {
next = next * 1103515245 + 12345;
}
@property bool empty() { return false; }
private:
uint next;
}
及返回它的函数:
RandomNumberGenerator generator(uint seed) {
return RandomNumberGenerator(seed);
}
还有一个可爱的程序,可打印出10个此数字:
import std.stdio;
import rnd;
void main() {
int count;
foreach (n; generator(5)) {
writeln(n);
if (++count == 10)
break;
}
}
结果是:
26298
25347
52004
26314
22713
9193
9426
118
36355
10786
但是,它有些烦人.我真正关心的是rnd.generator函数,但是RandomNumberGenerator类型自身就在那里.它像是失败的封装,因为它在生成器抽象之外泄漏了.
可用私属性标记它,rnd以外模块无法访问它.但它仍然在那,超出了它所属的空间,及其他模块成员仍然可访问它,私有与否(在D中,私声明不会隐藏同一模块中的其他声明).此外,我希望它很干净,它会发出吱吱声.
现在谈谈有趣的.
首先,D允许推导声明类型,所以可写如下内容:
auto g = RandomNumberGenerator(seed);
g自动为随机数生成器,这是标准的.
接着,可推导出函数的返回类型:
auto square(double d) {
return d * d;
}
auto x = square(2.3);
因为这是中语句式,编译器会把返回square的类型设置为double.当然,也会推导x为双精.现在重新组织生成器函数,如下:
module rnd;
auto generator(uint seed) {
struct RandomNumberGenerator {
@property int front() {
return ((seed / 0x10000) * seed) >> 16;
}
void popFront() {
seed = seed * 1103515245 + 12345;
}
@property bool empty() { return false; }
}
RandomNumberGenerator g;
g.popFront(); // 让他跑
return g;
}
随机数生成器成为在生成器的域内的一个类型.它在生成器外根本不可见.不能命名它,因此它是隐藏类型.
只能通过推导类型来取它的实例:
auto g = generator(5);
然后使用g.使用typeof并声明另一个RandomNumberGenerator:
auto g = generator(4);
typeof(g) h;
抱歉,这不行,编译器禁止在区间外实例化隐藏类型(原因是它无种子局部变量的引用).
最后细节很恼火.循环:
int count;
foreach (n; generator(5)) {
writeln(n);
if (++count == 10)
break;
}
只是很老套.使用区间,可省略许多循环,取而代之的是使用区间的取来仅抓取区间的前10个元素:
void main() {
foreach (n; take(generator(5), 10))
writeln(n);
}
然后使用writeln来完全摆脱循环:
void main() {
writeln(take(generator(5), 10));
}
给定T类型,及可从与T有定义关系的T中提取的U类型,那么U是存在的.
如,如果看到T指针类型,可继承U指向的现有类型:
import std.stdio;
void extractU(T)(T t) {
static if (is(T U : U*))
writefln("%s类型是%s的指针", typeid(T), typeid(U));
else
writefln("%s类型不是%s的指针", typeid(T));
}
void main() {
int* t;
extractU(t);
double d;
extractU(d);
}
打印:
int*是int的指针
double不是.
结论
在D中,隐藏类型是个令人高兴的发现,并且按可用但不命名的封装类型来启用令人满意的技术.
浙公网安备 33010602011771号