opDispatch và opApply

Trong kiểu ghép hay lớp, D cho phép bạn định nghĩa lại các toán tử +, -, phép gọi hàm (). Liên quan đến khả năng này, ta sẽ bàn kỹ hơn về hai hàm opDispatchopApply.

opDispatch

Các kiểu ghép hay lớp có thể định nghĩa hàm thành phần opDispatch để thay cho bất kỳ hàm thành phần nào chưa được định nghĩa tường minh. opDispatch nhận tên hàm thành phần chưa biết như là tham số mẫu, ở dạng chuỗi. Ta còn nói opDispatch là hàm catch-all; nó cho phép một mức khác của việc lập trình tổng quát (generic programming) tại lúc biên dịch mã nguồn.

struct C {
    void callA(int i, int j) { ... }
    void callB(string s) { ... }
}
struct CallLogger(C) {
    C content;
    void opDispatch(string name, T...)(T vals) {
        writeln("called ", name);
        mixin("content." ~ name)(vals);
    }
}
CallLogger!C l;
l.callA(1, 2);
l.callB("ABC");

opApply

Thay vì định nghĩa kiểu dải (range) riêng để dùng với phép lặp foreach, ta có thể định nghĩa toán tử opApply như là hành thành phần. Khi duyệt với foreach, hàm opApply sẽ được gọi với tham số là một ủy nhiệm hàm đặc biệt:

class Tree {
    Tree lhs;
    Tree rhs;
    int opApply(int delegate(Tree) dg) {
        if (lhs && lhs.opApply(dg)) return 1;
        if (dg(this)) return 1;
        if (rhs && rhs.opApply(dg)) return 1;
        return 0;
    }
}
Tree tree = new Tree;
foreach(node; tree) {
    ...
}

Trình biên dịch chuyển hóa thân của foreach thành một ủy nhiệm hàm đặc biệt, trở thành đối tượng dùng như tham số của opApply. Tham số duy nhất của ủy nhiệm hàm chứa giá trị hiện tại của phép lặp. Kiểu trả về là int, và nếu nó không phải là 0, phép lặp sẽ phải dừng lại.

In-depth

rdmd playground.d