对类,不能重载​​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);

函数名

示例

​opIndex​

集合[i]

​opIndexAssign​

集合[i] = 7

​opIndexUnary​

++集合[i]

​opIndexOpAssign​

集合[i] *= 2

​opDollar​

集合[$ - 1]

​opSlice​

集合[]

​opSlice(正,正)​

集合[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, " 工作时间");
}
}
}