对类,不能重载opAssign
,因为类
是按引用的.赋值是引用.
重载运算符,主要是为了方便书写
.
struct TimeOfDay {
// ...
ref TimeOfDay opOpAssign(string op)(in Duration duration)//(1)
if (op == "+") { //(2)
minute += duration.minute;
hour += minute / 60;
minute %= 60;hour %= 24;
return this;//本为引用?
}
}
opOpAssign(string op),表示是赋值大类
下面的重载
opOpAssign!"+"就是+=
符的重载,注意,返回的是引用
.
与c++
不一样,c++
的本
是指针.而d
是引用
.
要注意,重载的函数的语义
最好是直观的,不要瞎搞.
可重载的操作符有:
一元操作符:
操作符 | 意思 | 串 |
| 取反 | “-” |
| 与+一样 | “+” |
| 按位取反 | “~” |
| 访问指针 | “*” |
| 加1 | “++” |
| 减1 | “–” |
不能自定义后++与后--
,编译器给你搞
二元操作符:
+ - * / % ^^ & ^ << >> >>> ~ in == != < <= > >= = += -= *= /= %= ^^= &= ^= <<= >>= >>>= ~=
有两种:
x 操作 y
,
x.opBinary!"op"(y);
y.opBinaryRight!"op"(x);
函数名 | 示例 |
| 集合[i] |
| 集合[i] = 7 |
| ++集合[i] |
| 集合[i] *= 2 |
| 集合[$ - 1] |
| 集合[] |
| 集合[i…j] |
还有opCall((...)),opCast(转!...),opDispatch(未知函数)
struct Duration {
int minute;
ref Duration opUnary(string op)()
if ((op == "++") || (op == "--")) {
mixin (op ~ "minute;");
return this;
}
ref Duration opOpAssign(string op)(in int amount)
if ((op == "+") || (op == "-")) {
//(op == "*") || (op == "/")) {//扩展
mixin ("minute " ~ op ~ "= amount;");
return this;
}
ref Duration opOpAssign(string op)(in int amount)
//不要限制了.
mixin ("minute " ~ op ~ "= amount;");
return this;
}
}
int i = 1;
writeln(":", &i);
writeln(":", &(++i));
//看看地址
修改自身的有opUnary!"++", opUnary!"--"
及所有opOpAssign
重载.
opEquals,必须返回极
in
一般返回对象,也可返回极
.
表示<, <=, >, 和 >=
的opCmp
返回整
创建新对象的操作符:一元-, +, ~;二元~
.及
算术操作:+, -, 星, /, %, 和 ^^
,
按位操作&, |, ^, <<, >>, 和 >>>
和opAssign
,有时op赋值
会返回常 引用
(钥匙).而不是实体.
opDollar
返回容器元素个数
未限制操作符:
一元 星, opCall, opCast, opDispatch, opSlice, 和所有opIndex
opEquals 和 opCmp
必须一致,如果相等,则比较必须为0
.一般可以不定义相等
操作,编译器自动生成.
有些需要不同的相等定义,可以定义一个.
opCmp
用于排序
.可以控制<,<=,>,>=
,返回类型为整
.
如左在右前,则返回负,左在右后,返回正.相等为0
.
int opCmp(in TimeOfDay rhs) const {
return (hour == rhs.hour
? minute - rhs.minute
: hour - rhs.hour);
}//注意,减号可能导致溢出.
struct S {
int i;
int opCmp(in S rhs) const {
return i - rhs.i; // 漏洞
}//-2比`最大整更大`?.
}
void main() {
assert(S(-2) > S(int.max)); // 错误排序
}
//算法改进
import std.algorithm;
struct S {
string name;
int opCmp(in S rhs) const {
return cmp(name, rhs.name);//字母序比较
}
}
opCall()
用于调用函数.
static opCall()
,用来静态创建默认()
定义opCall()
禁止了编译器自动生成的构造函数
因此这样用:
struct LinearEquation {
double a;
double b;
double opCall(double x) const {
return a * x + b;
}
}
//这样用
LinearEquation equation = { 1.2, 3.4 };
double y = equation(5.6);//像函数一样使用
下面是个双端队列
import std.stdio;
import std.string;
import std.conv;
struct DoubleEndedQueue //也叫双列
{
private:
int[] head; //头列
int[] tail; //尾列
ref inout(int) elementAt(size_t index) inout {
return (index < head.length
? head[$ - 1 - index]
: tail[index - head.length]);
}//实际切片
public:
string toString() const {
string result;
foreach_reverse (element; head) {
result ~= format("%s ", to!string(element));
}
foreach (element; tail) {
result ~= format("%s ", to!string(element));
}
return result;
}
version (none) {//tostring的简单有效实现
void toString(void delegate(const(char)[]) sink) const {
import std.format;
import std.range;
formattedWrite(//格式写
sink, "%(%s %)", chain(head.retro, tail));
}}
void insertAtHead(int value) {
head ~= value;
}//加元素,加至头
ref DoubleEndedQueue opOpAssign(string op)(int value)
if (op == "~") {
tail ~= value;
return this;
}//加至尾
inout(int) opIndex(size_t index) inout {
return elementAt(index);
}//[]操作
int opIndexUnary(string op)(size_t index) {
mixin ("return " ~ op ~ "elementAt(index);");
}//一元式
int opIndexAssign(int value, size_t index) {
return elementAt(index) = value;
}
int opIndexOpAssign(string op)(int value, size_t index) {
mixin ("return elementAt(index) " ~ op ~ "= value;");
}//[i]+=右
size_t opDollar() const {
return head.length + tail.length;
}
}
void main() {
auto deque = DoubleEndedQueue();
foreach (i; 0 .. 10) {
if (i % 2) {
deque.insertAtHead(i);
} else {
deque ~= i;
}
}
writefln("[3]元素: %s",deque[3]);//访问元素
++deque[4]; // 加元素
deque[5] = 55; // 给元素赋值
deque[6] += 66; // 加至元素
(deque ~= 100) ~= 200;
writeln(deque);
}
(deque ~= 100) ~= 200;
因为,~=
为引用类型.
deque[] *= 10; //每个元素*
// 等价于
{
auto range = deque.opSlice();
range.opOpAssign!"*"(10);//区间切片再*
}
再如:
import std.exception;
struct DoubleEndedQueue {
// ...
inout(Range) opSlice() inout {//返回区间
return inout(Range)(head[], tail[]);
}
inout(Range) opSlice(size_t begin, size_t end) inout {//区间[头..尾]
enforce(end <= opDollar());
enforce(begin <= end);
if (begin < head.length) {
if (end < head.length) {//区间全在头内
return inout(Range)(head[$ - end .. $ - begin],[]);
} else {//部分在头,部分在尾
return inout(Range)(head[0 .. $ - begin],tail[0 .. end - head.length]);
}
} else {//完全在尾
return inout(Range)([],tail[begin - head.length .. end - head.length]);
}
}
struct Range {//区间细节
int[] headRange,tailRange;
Range opUnary(string op)() {//一元操作
mixin (op ~ "headRange[];");
mixin (op ~ "tailRange[];");
return this;
}
Range opAssign(int value) {//赋值
headRange[] = value;
tailRange[] = value;return this;
}
Range opOpAssign(string op)(int value) {
mixin ("headRange[] " ~ op ~ "= value;");
mixin ("tailRange[] " ~ op ~ "= value;");
return this;
}//赋值操作
}
}
void main() {
auto deque = DoubleEndedQueue();
foreach (i; 0 .. 10) {
if (i % 2) deque.insertAtHead(i);
else {deque ~= i;}
}
writeln(deque);deque[] *= 10;
deque[3 .. 7] = -1;writeln(deque);
}
opCast
转换类型,是个模板.
opDispatch
,最后的调用.包揽所有.
import std.stdio;
import std.conv;
struct Duration {
int hour;
int minute;
double opCast(T : double)() const {
return hour + (to!double(minute) / 60);
}//可按这种方式转成`双精`
bool opCast(T : bool)() const {
return (hour != 0) || (minute != 0);
}//逻辑表达式中,可以自动调用这个转换.
}//而其他转换,得显式调用.
void main() {
auto duration = Duration(2, 30);
double d = to!double(duration);
writeln(d);
}
void foo(bool b) {
// ...
}
foo(duration);//不行,编译不过
bool b = duration;//不行,编译不过
暴力指派函数,最后的函数.
import std.stdio;
struct Foo {
void opDispatch(string name, T)(T parameter) {
writefln("Foo.opDispatch - name: %s, value: %s",name, parameter);
}
}
void main() {
Foo foo;
foo.aNonExistentFunction(42);
foo.anotherNonExistentFunction(100);
}
还有二元的在
:opBinaryRight!“in”
if (time in lunchBreak) {
//等价于
if (lunchBreak.opBinaryRight!"in"(time)) {
//应该叫in的右二元操作
//-----
import std.stdio;
import std.string;
struct Duration {int minute;}
struct TimeOfDay {
int hour;int minute;
ref TimeOfDay opOpAssign(string op)(in Duration duration)
if (op == "+") {
minute += duration.minute;
hour += minute / 60;
minute %= 60;hour %= 24;
return this;
}
int opCmp(in TimeOfDay rhs) const {
return (hour == rhs.hour
? minute - rhs.minute
: hour - rhs.hour);
}
string toString() const {
return format("%02s:%02s", hour, minute);
}
}
struct TimeSpan {
TimeOfDay begin;
TimeOfDay end; // 尾端
bool opBinaryRight(string op)(TimeOfDay time) const
if (op == "in") {
return (time >= begin) && (time < end);
}
}
void main() {
auto lunchBreak = TimeSpan(TimeOfDay(12, 00),
TimeOfDay(13, 00));
for (auto time = TimeOfDay(11, 30);
time < TimeOfDay(13, 30);
time += Duration(15)) {
if (time in lunchBreak) {
writeln(time, " 吃饭时间");
} else {
writeln(time, " 工作时间");
}
}
}