50用d编程区间2
容器,算法,区间
都是模板
std.range
包含许多按模板限制
与static if
的模板示例.
区间类型模板
.
isInputRange isForwardRange isBidirectionalRange isRandomAccessRange isOutputRange
void print(T)(T range)
if (isInputRange!T) {//要求是输入区间
// ...
}
void foo(T)(T range)
if (isOutputRange!(T, double)) {//两个参数
//1,区间类型,2,元素类型.
// ...
}
//与`static if`连用,可以决定用户定义区间的能力
struct Negative(T)
if (isInputRange!T) {
T range;
@property bool empty() {
return range.empty;
}
@property auto front() {
return -range.front;
}//负
void popFront() {
range.popFront();
}
}
如是前向区间,就可用save
函数.
返回类型可指定为ElementType!T
方便函数:
Negative!T negative(T)(T range) {
return Negative!T(range);
}
示例:
struct FibonacciSeries {
int current = 0;int next = 1;
enum empty = false;
@property int front() const {
return current;
}
void popFront() {
const nextNext = current + next;
current = next;
next = nextNext;
}
@property FibonacciSeries save() const {
return this;
}
}
// ...
writeln(FibonacciSeries().take(5).negative);
这样是不行的
writeln(FibonacciSeries()
.take(5)
.negative
.cycle // 编译错误,前向区间
.take(10));
加上下面,就可编译了.
static if(isForwardRange!T){//如果T为前向区间
@property Negative save(){
return Negative(range.save);
}//赋予保存,自身也是前向区间了.
}
还可以加上双向
,随机
区间:
static if(isBidirectionalRange!T){
@property auto back(){
return -range.back;
}
void popBack(){
range.popBack();
}
}
static if(isRandomAccessRange!T){
auto opIndex(size_t index){
return -range [index];
}
}
可用
auto d = [ 1.5, 2.75 ];
auto n = d.negative;
writeln(n[1]);
访问了.
元素类型与元素编码类型,类似c++的值类型
…
void foo(I1, I2, O)(I1 input1, I2 input2, O output)
if (isInputRange!I1 &&
isForwardRange!I2 &&
isOutputRange!(O, ElementType!I1)) {
//O为输出区间类型,接受I1的元素类型
// ...
}
因而ElementType!string 和 ElementType!wstring是dchar.
因为串是自动解码为dchar
的.串当作数组时是dchar
的区间.串的实际编码类型可由ElementEncodingType
取得.
更多区间模板:
isInfinite,是无穷,
hasLength,有长度属性
hasSlicing,有切片,即是否支持a[x…y]
hasAssignableElements,当前(front
)的返回类型是否可赋值
hasSwappableElements,区间元素是否可交换(算法里面)
hasMobileElements,是否可移动.有这moveFront(), moveBack(),或moveAt()
三个函数
hasLvalueElements,区间元素是左值.(既不是实际元素的拷贝,也不是栈上的临时对象)
hasLvalueElements!FibonacciSeries
为假,因为其不是系列元素值,只是单个front
值.hasLvalueElements!(Negative!(int[]))
也是假,因为切片
不是拥有实际值,里面的模板参数
只是返回实际切片元素的负号.而hasLvalueElements!(int[])
是真,因为确实提供访问元素值.
//这些搞得很难懂.
struct Negative(T)
if (isInputRange!T) {
// ...
static if (isInfinite!T) {
// Negative!T 也是无穷
enum empty = false;
} else {
@property bool empty() {
return range.empty;
}
}
// ...
}
static assert( isInfinite!(Negative!FibonacciSeries));
static assert(!isInfinite!(int[]));
模板实现的区间,展示了编译时
多态.
编译时多态要处理不同的类型,的实例化.
如take
模板的返回类型与原来的区间有关.
writeln(typeof([11, 22].negative.take(1)).stringof);
writeln(typeof(FibonacciSeries().take(1)).stringof);
//输出:
Take!(Negative!(int[]))
Take!(FibonacciSeries)
因而不同类型不能相互赋值,
auto range = [11, 22].negative;
// ... 稍后 ...
range = FibonacciSeries();//编译错误,不能转换
d标准库
提供了inputRangeObject()和outputRangeObject()
.这种输入区间对象
能支持4种
区间(除了输出区间的那4种)(InputRange, ForwardRange, BidirectionalRange, 和 RandomAccessRange)
InputRange!int range = [11, 22].negative.inputRangeObject;
//必须明确指定返回类型,不能用`auto`定义.
// ... 稍后...
range=FibonacciSeries().inputRangeObject;
//编译
取其输入区间
对象,感觉还是折腾
再如.
ForwardRange!int range = [11, 22].negative.inputRangeObject;
auto copy = range.save;
range = FibonacciSeries().inputRangeObject;
writeln(range.save.take(10));
调用save
,输出区间对象与输出区间
搭配.允许输出区间的再操作们作为相同类型.
【推荐】国内首个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岁的心里话
· 按钮权限的设计及实现