d中的后期静态绑定

d中的后期静态绑定,d,D,我正在开发一个通用的集合类模板,比如说List(T),在这里我希望能够做一些类似php的后期静态绑定的事情。最好用一些简化的示例代码来说明。这段代码编译得很好,就像在dmd上一样,但它需要一个小的更改才能成为我想要的方式 module main; import std.stdio; import std.string; class List(T) { private T[] _list; public void append(T t) { _list

我正在开发一个通用的集合类模板,比如说
List(T)
,在这里我希望能够做一些类似php的后期静态绑定的事情。最好用一些简化的示例代码来说明。这段代码编译得很好,就像在dmd上一样,但它需要一个小的更改才能成为我想要的方式

module main;

import std.stdio;
import std.string;

class List(T)
{
    private T[] _list;

    public void append(T t)
    {
        _list ~= t;
    }

    // this is where some help is needed...
    public List select(bool delegate(T t) dg)
    {
            // auto should be whatever subclass of List(T) is calling this method.
        auto result = new List!T();
        foreach(t; _list)
        {
            if (dg(t)) result.append(t);
        }
        return result;
    }

    int opApply(int delegate(ref T) dg)
    {
        int result = 0;

        for (int i = 0; i < _list.length; i++)
        {
            result = dg(_list[i]);
            if (result)
                break;
        }
        return result;
    }
}

enum Gender
{
    MALE,
    FEMALE,
    SECRET
}

class Person
{
    private string _firstName;
    private string _lastName;
    private string _email;
    private Gender _gender;

    @property public string firstName() {return _firstName;}
    @property public string lastName() {return _lastName;}
    @property public string email() {return _email;}
    @property public Gender gender() {return _gender;}


    public this()
    {
    }

    public this(string firstName, string lastName, Gender gender = Gender.SECRET, string email = "info@example.com")
    {
        this();

        this._firstName = firstName;
        this._lastName = lastName;
        this._gender = gender;
        this._email = email;
    }

    override public string toString()
    {
        if (email.length > 0)
        {
            return "%s %s <%s>".format(firstName, lastName, email);
        }
        else
        {
            return "%s %s".format(firstName, lastName);
        }
    }
}

class PeopleList : List!Person
{
    // I would like to be able to make this: public PeopleList selectByGender(Gender gender)
    public List!Person selectByGender(Gender gender)
    {
        return select(p => p.gender == gender);
    }
}

void main(string[] args)
{
    auto people = new PeopleList();
    people.append(new Person("Kris", "Herlaar", Gender.MALE));
    people.append(new Person("John", "Doe", Gender.MALE));
    people.append(new Person("Steve", "Wozniak", Gender.MALE));
    people.append(new Person("Walter", "Bright", Gender.MALE));
    people.append(new Person("Amelia", "Earhart", Gender.FEMALE, null));
    people.append(new Person("Susan", "Anthony", Gender.FEMALE, null));

    foreach(p; people.selectByGender(Gender.FEMALE))
    {
        writeln(p);
    }
}
主模块;
进口std.stdio;
输入标准字符串;
班级名单(T)
{
私人T[]_名单;
公共无效附加(T)
{
_list~=t;
}
//这就是需要帮助的地方。。。
公共列表选择(bool代表(T)dg)
{
//auto应该是List(T)调用此方法的任何子类。
自动结果=新列表!T();
foreach(t;_列表)
{
if(dg(t))结果追加(t);
}
返回结果;
}
内部opApply(内部代表(参考T)dg)
{
int结果=0;
对于(int i=0;i<\u list.length;i++)
{
结果=dg(_列表[i]);
如果(结果)
打破
}
返回结果;
}
}
枚举性别
{
男,,
女,,
秘密
}
班主任
{
私有字符串_firstName;
私有字符串_lastName;
私人字符串\u电子邮件;
私人性别;
@属性公共字符串firstName(){return\u firstName;}
@属性公共字符串lastName(){return\u lastName;}
@属性public string email(){return\u email;}
@属性公共性别(){return\u Gender;}
公开这个()
{
}
public this(string firstName,string lastName,Gender=Gender.SECRET,string email=”info@example.com")
{
这个();
这个。_firstName=firstName;
这是。_lastName=lastName;
这._性别=性别;
这个。_email=电子邮件;
}
重写公共字符串toString()
{
如果(email.length>0)
{
返回“%s%s”。格式(名字、姓氏、电子邮件);
}
其他的
{
返回“%s%s”。格式(firstName,lastName);
}
}
}
班级名单:名单!人
{
//我希望能够做到这一点:公共人物列表按性别选择(性别)
公共列表!按性别选择的人员(性别)
{
返回select(p=>p.gender==gender);
}
}
void main(字符串[]args)
{
自动人员=新人员列表();
人物。附加(新人物(“克里斯”,“赫拉尔”,性别。男性));
people.append(新人物(“约翰”,“多伊”,“性别.男性”);
追加(新人物(“史蒂夫”,“沃兹尼亚克”,性别,男性));
人物。附加(新人物(“沃尔特”,“布莱特”,性别。男性));
people.append(新人物(“阿米莉亚”、“埃尔哈特”、性别、女性、空));
people.append(新人物(“Susan”,“Anthony”,Gender.femal,null));
foreach(p;people.selectByGender(Gender.femal))
{
writeln(p);
}
}
如何确保
PeopleList.select也会返回
PeopleList
的实例,而不是
列表!Person
,以便注释掉的
selectByGender
声明正确吗

我可能可以在实现中使用
Object.factory(this.classinfo.name)
进行模拟,并实际获得
result
的正确实例类型,但我认为这对声明的返回类型没有帮助

我想使链接方法成为可能,因此我需要编译器允许我返回调用
List(T)的任何子类的实例。选择
我想这可以通过嵌套模板来完成,但还没有找到任何可以编译的方法,更不用说看起来很优雅了

回复收到的反馈的其他信息


我知道现实生活中的
std.algorithm
filter
;这段代码并不代表一个实际的用例,而是一个了解D及其模板的更多能力/限制的思想实验。

这是继承的一个不幸用法
PersonList
不应该存在:它无论如何都不是polymorhpic

我认为您打算做的是提供一个助手方法:从列表中按性别选择人。 D有一种称为统一函数调用语法的东西,它允许您调用自由函数,就好像第一个参数是实际的
这个
实例一样。所以你可以像这样重写你的代码:

public List!People selectByGender(List!People list, Gender gender)
{
    return list.select(p => p.gender == gender);
}

void main(string[] args)
{
    auto people = new List!People();

    // ...

    foreach(p; people.selectByGender(Gender.FEMALE))
    {
        writeln(p);
    }
}
我不知道你是否研究过std算法。但它基本上会使所有的
列表(T)
代码变得多余。您可以用您的人员创建一个数组(或任何其他
范围
人员
),然后执行以下操作:

foreach (p; people.filter!(p => p.gender == Gender.FEMALE))
{
    writeln(p);
}
就这样吧。这种风格类似于函数式编程、管道和过滤器或组件编程(在D社区中),无论您如何称呼它。另外,
filter
等不会分配新的列表,而是动态、延迟或流式地从原始数组生成结果。您可以使用std.array中的
array
,强制他们将结果保存在新的缓冲区中


这是强迫自己在继承层次结构中思考并不是最优雅的方式的基本情况之一。

您可以使用
模板设置此参数,如中所述

下面是页面中的一些示例代码

interface Addable(T) {
    final R add(this R)(T t) {
        return cast(R)this; // cast is necessary, but safe
    }
}

class List(T) : Addable!T {
    List remove(T t) {
        return this;
    }
}

void main() {
    auto list = new List!int;
    list.add(1).remove(1); // ok
}
这是你使用它的代码

module main;

import std.stdio;
import std.string;

class List(T)
{
    private T[] _list;

    public void append(T t)
    {
        _list ~= t;
    }

    // select is now templatized based on the most derived class
    public This select(this This)(bool delegate(T t) dg)
    {
        // auto should be whatever subclass of List(T) is calling this method.
        auto result = new This();
        foreach(t; _list)
        {
            if (dg(t)) result.append(t);
        }
        return result;
    }

    int opApply(int delegate(ref T) dg)
    {
        int result = 0;

        for (int i = 0; i < _list.length; i++)
        {
            result = dg(_list[i]);
            if (result)
                break;
        }
        return result;
    }
}

enum Gender
{
    MALE,
    FEMALE,
    SECRET
}

class Person
{
    private string _firstName;
    private string _lastName;
    private string _email;
    private Gender _gender;

    @property public string firstName() {return _firstName;}
    @property public string lastName() {return _lastName;}
    @property public string email() {return _email;}
    @property public Gender gender() {return _gender;}


    public this()
    {
    }

    public this(string firstName, string lastName, Gender gender = Gender.SECRET, string email = "info@example.com")
    {
        this();

        this._firstName = firstName;
        this._lastName = lastName;
        this._gender = gender;
        this._email = email;
    }

    override public string toString()
    {
        if (email.length > 0)
        {
            return "%s %s <%s>".format(firstName, lastName, email);
        }
        else
        {
            return "%s %s".format(firstName, lastName);
        }
    }
}

class PeopleList : List!Person
{
    public PeopleList selectByGender(Gender gender)
    {
        return this.select(p => p.gender == gender);
    }
}

void main(string[] args)
{
    auto people = new PeopleList();
    people.append(new Person("Kris", "Herlaar", Gender.MALE));
    people.append(new Person("John", "Doe", Gender.MALE));
    people.append(new Person("Steve", "Wozniak", Gender.MALE));
    people.append(new Person("Walter", "Bright", Gender.MALE));
    people.append(new Person("Amelia", "Earhart", Gender.FEMALE, null));
    people.append(new Person("Susan", "Anthony", Gender.FEMALE, null));

    foreach(p; people.selectByGender(Gender.FEMALE))
    {
        writeln(p);
    }
}
主模块;
进口std.stdio;
输入标准字符串;
班级名单(T)
{
私人T[]_名单;
公共无效附加(T)
{
_list~=t;
}
//select现在基于最派生的类进行模板化
公共本选择(本)(bool代表(T)dg)
{
//auto应该是List(T)调用此方法的任何子类。
自动结果=新建此();
foreach(t;_列表)
{
if(dg(t))结果追加(t);
}
返回结果;
}
内部opApply(内部代表(参考T)dg)
{
int结果=0;
对于(int i=0;i<\u list.length;i++)