本文介绍了D中的后期静态绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究一个通用的集合类模板,比如说 List(T),在这里我希望能够做类似php的后期静态绑定之类的事情。最好用一些简化的示例代码来说明。这段代码可以像在dmd上一样编译良好,但是我需要做一点改动。

I'm working on a generic collection class template, let's say List(T) where i'd like to be able to do something like php's late static binding. Might be best illustrated with some simplified sample code. This code compiles fine as is on dmd, but it needs a small change to be the way I want.

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);
    }
}

我将如何确保 PeopleList.select 还将返回 PeopleList 的实例,而不是 List!Person ,这样注释为 selectByGender 的声明正确吗?

How would I go about making sure that PeopleList.select would also return an instance of PeopleList instead of a List!Person so that the commented out declaration of selectByGender is correct?

我可能可以在实现中用 Object.factory(this.classinfo.name)嘲笑一下,实际上可以 result 的正确实例类型,但是我认为这对声明的return-type没有帮助。

I could probably mock about with Object.factory(this.classinfo.name) inside the implementation and actually get the correct type of instance for result but I figure that would not help with the declared return-type.

我想使链接方法成为可能,所以我需要编译器允许我返回任何正在调用 List的子类的实例。 T).select 我想可以用嵌套模板来完成,但是还不能提出任何可以编译的东西,更不用说看起来很优雅了。

I'd want to make chaining methods possible so I'd need the compiler to allow me to return instances of whatever subclass is calling List(T).select I imagine it could be done with a nested template, but haven't been able to come up with anything that would compile, let alone seem elegant.

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

我知道 std.algorithm 过滤器,在现实生活中;这段代码并不代表实际的用例,而是一个思想实验,旨在学习D及其模板的更多功能/限制。

I am aware of std.algorithm and of filter, In real life; this code does not represent an actual use-case but a thought experiment to learn more of the abilities/limits of D and its' templates.

推荐答案

您可以按照

You can use Template This Parameters as described in http://dlang.org/template.html#TemplateThisParameter

以下是页面中的示例代码。

Here's some example code from the page.

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);
    }
}

这篇关于D中的后期静态绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 02:16