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中,隐藏类型
是个令人高兴
的发现,并且按可用但不命名
的封装类型
来启用令人满意的技术.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现