Как использовать чистый в D 2.0

Я обычно использую интерфейсы только там, где это имеет смысл в небольших проектах. Тем не менее, моя последняя работа имеет большой проект, где почти каждый объект домена имеет интерфейс. Это, вероятно, излишне и определенно раздражает, но то, как мы проводим тестирование и используем Spring для внедрения зависимостей, требует этого.

10
задан Richard JP Le Guen 14 March 2013 в 03:16
поделиться

4 ответа

Пожалуйста, просмотрите определение чистых функций:

Чистые функции - это функции, которые производят одинаковый результат для одних и тех же аргументов. С этой целью чистая функция:

  • имеет параметры, которые все инвариантны или неявно конвертируются в инвариант.
  • не читает и не записывает какое-либо глобальное изменяемое состояние

. Одним из эффектов использования чистых функций является то, что они могут безопасно распараллеливать. Однако это '

3
ответ дан 4 December 2019 в 00:26
поделиться

Просто догадка, но эта функция не всегда возвращает один и тот же результат.

Видите, она возвращает ссылку на какой-то объект, и хотя объект всегда будет содержать одни и те же данные, объекты, возвращаемые несколькими вызовами одних и тех же функций, не идентичны; то есть у них разные адреса памяти.

Когда вы возвращаете ссылку на объект, вы, по сути, возвращаете адрес памяти, который будет отличаться в разных вызовах.

Другой способ представления: часть возвращаемого значения - это адрес памяти. объекта, который зависит от некоторого глобального состояния (состояний), и если вывод функции зависит от глобального состояния, то он не чистый. Черт, это даже не должно от этого зависеть; пока функция читает глобальное состояние, это не чисто. Называя «новым»,

-1
ответ дан 4 December 2019 в 00:26
поделиться

Другие уже указали, что addMsg не является чистым и не может быть чистым, потому что он изменяет состояние объекта.

Единственный способ сделать его чистым - это инкапсулировать вносимые вами изменения. Самый простой способ сделать это - использовать мутацию return, и есть два способа реализовать это.

Во-первых, вы можете сделать это так:

class TestPure
{
    string[] msg;
    pure TestPure addMsg(string s)
    {
        auto r = new TestPure;
        r.msg = this.msg.dup;
        r.msg ~= s;
        return r;
    }
}

Вам нужно скопировать предыдущий массив, потому что внутри чистой функции this ссылка на самом деле является константой. Обратите внимание, что вы могли бы сделать копию лучше, выделив новый массив окончательного размера, а затем скопировав элементы в себя. Вы могли бы использовать эту функцию так:

pure TestPure run3()
{
    auto t = new TestPure;
    t = t.addMsg("Test");
    t = t.addMsg("this.");
    return t;
}

Таким образом, мутация ограничивается каждой чистой функцией с изменениями, передаваемыми через возвращаемые значения.

Альтернативный способ написания TestPure состоял бы в том, чтобы сделать члены константными и выполнять все перед передачей в конструктор:

class TestPure
{
    const(string[]) msg;
    this()
    {
        msg = null;
    }
    this(const(string[]) msg)
    {
        this.msg = msg;
    }
    pure TestPure addMsg(string s)
    {
        return new TestPure(this.msg ~ s);
    }
}

Надеюсь, что это поможет.

Самый простой способ сделать это - использовать мутацию return, и есть два способа реализовать это.

Во-первых, вы можете сделать это так:

class TestPure
{
    string[] msg;
    pure TestPure addMsg(string s)
    {
        auto r = new TestPure;
        r.msg = this.msg.dup;
        r.msg ~= s;
        return r;
    }
}

Вам нужно скопировать предыдущий массив, потому что внутри чистой функции this ссылка на самом деле является константой. Обратите внимание, что вы могли бы сделать копию лучше, выделив новый массив окончательного размера, а затем скопировав элементы в себя. Вы могли бы использовать эту функцию так:

pure TestPure run3()
{
    auto t = new TestPure;
    t = t.addMsg("Test");
    t = t.addMsg("this.");
    return t;
}

Таким образом, мутация ограничивается каждой чистой функцией с изменениями, передаваемыми через возвращаемые значения.

Альтернативный способ написания TestPure состоял бы в том, чтобы сделать члены константными и выполнять все перед передачей в конструктор:

class TestPure
{
    const(string[]) msg;
    this()
    {
        msg = null;
    }
    this(const(string[]) msg)
    {
        this.msg = msg;
    }
    pure TestPure addMsg(string s)
    {
        return new TestPure(this.msg ~ s);
    }
}

Надеюсь, что это поможет.

Самый простой способ сделать это - использовать мутацию return, и есть два способа реализовать это.

Во-первых, вы можете сделать это так:

class TestPure
{
    string[] msg;
    pure TestPure addMsg(string s)
    {
        auto r = new TestPure;
        r.msg = this.msg.dup;
        r.msg ~= s;
        return r;
    }
}

Вам нужно скопировать предыдущий массив, потому что внутри чистой функции this ссылка на самом деле является константой. Обратите внимание, что вы могли бы сделать копию лучше, выделив новый массив окончательного размера, а затем скопировав элементы в себя. Вы могли бы использовать эту функцию так:

pure TestPure run3()
{
    auto t = new TestPure;
    t = t.addMsg("Test");
    t = t.addMsg("this.");
    return t;
}

Таким образом, мутация ограничивается каждой чистой функцией с изменениями, передаваемыми через возвращаемые значения.

Альтернативный способ написания TestPure состоял бы в том, чтобы сделать члены константными и выполнять все перед передачей в конструктор:

class TestPure
{
    const(string[]) msg;
    this()
    {
        msg = null;
    }
    this(const(string[]) msg)
    {
        this.msg = msg;
    }
    pure TestPure addMsg(string s)
    {
        return new TestPure(this.msg ~ s);
    }
}

Надеюсь, что это поможет.

class TestPure
{
    string[] msg;
    pure TestPure addMsg(string s)
    {
        auto r = new TestPure;
        r.msg = this.msg.dup;
        r.msg ~= s;
        return r;
    }
}

Вам нужно скопировать предыдущий массив, потому что внутри чистой функции ссылка this на самом деле является константой. Обратите внимание, что вы могли бы сделать копию лучше, выделив новый массив окончательного размера, а затем скопировав элементы в себя. Вы могли бы использовать эту функцию так:

pure TestPure run3()
{
    auto t = new TestPure;
    t = t.addMsg("Test");
    t = t.addMsg("this.");
    return t;
}

Таким образом, мутация ограничивается каждой чистой функцией с изменениями, передаваемыми через возвращаемые значения.

Альтернативный способ написания TestPure состоял бы в том, чтобы сделать члены константными и выполнять все перед передачей в конструктор:

class TestPure
{
    const(string[]) msg;
    this()
    {
        msg = null;
    }
    this(const(string[]) msg)
    {
        this.msg = msg;
    }
    pure TestPure addMsg(string s)
    {
        return new TestPure(this.msg ~ s);
    }
}

Надеюсь, что это поможет.

class TestPure
{
    string[] msg;
    pure TestPure addMsg(string s)
    {
        auto r = new TestPure;
        r.msg = this.msg.dup;
        r.msg ~= s;
        return r;
    }
}

Вам нужно скопировать предыдущий массив, потому что внутри чистой функции ссылка this на самом деле является константой. Обратите внимание, что вы могли бы сделать копию лучше, выделив новый массив окончательного размера, а затем скопировав элементы в себя. Вы могли бы использовать эту функцию так:

pure TestPure run3()
{
    auto t = new TestPure;
    t = t.addMsg("Test");
    t = t.addMsg("this.");
    return t;
}

Таким образом, мутация ограничивается каждой чистой функцией с изменениями, передаваемыми через возвращаемые значения.

Альтернативный способ написания TestPure состоял бы в том, чтобы сделать члены константными и выполнять все перед передачей в конструктор:

class TestPure
{
    const(string[]) msg;
    this()
    {
        msg = null;
    }
    this(const(string[]) msg)
    {
        this.msg = msg;
    }
    pure TestPure addMsg(string s)
    {
        return new TestPure(this.msg ~ s);
    }
}

Надеюсь, что это поможет.

4
ответ дан 4 December 2019 в 00:26
поделиться

Я думаю , что ваш код концептуально верен. Однако вы могли встретить случай, когда семантический анализ компилятора не так хорош, как ваш мозг.

Рассмотрим случай, когда исходный код класса недоступен. В таких случаях компилятор не сможет сообщить, что addMsg изменяет только переменную-член, поэтому он не может позволить вам вызвать ее из чистой функции.

Чтобы разрешить это в вашем случае, он должен иметь специальную обработку для этого типа использования. Каждое добавленное правило особого случая усложняет язык (или, если его не задокументировать, делает его менее переносимым)

0
ответ дан 4 December 2019 в 00:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: