Эквивалент C # `readonly` ключевое слово в D? - PullRequest
7 голосов
/ 18 мая 2011

Из того, что я понимаю при чтении на D, при использовании ключевого слова immutable для переменной, значение переменной должно быть известно во время компиляции, в то время как readonly в C # не должно быть, а поля readonly может быть назначен в конструкторе класса с использованием нестатических значений. Возможно ли это в D?

Ответы [ 4 ]

10 голосов
/ 18 мая 2011

В D2 константный член может быть инициализирован только внутри конструктора (или непосредственно в объявлении класса, но не в обоих):

import io = std.stdio;

class A
{
    const int member;
    this(int nb)
    {
        this.member = nb;
    }
}

void main()
{
    A a = new A(12);
    io.writeln(a.member);
    //a.member = 14; //Error: can only initialize const member member inside constructor
}
6 голосов
/ 18 мая 2011

Поскольку, как представляется, существует некоторая путаница (как в исходном вопросе, так и в комментарии he_the_great) относительно неизменности, я подумал, что добавлю в сторону.

Когда вы говорите immutable int i = 42, вы говорите, что я не буду изменен, а не то, что это значение известно во время компиляции. immutable на самом деле является модификатором типа и создает новый тип. immutable T является сокращением для immutable(T). immutable(T) создает T, который никогда не может быть изменен, то есть, если вы прочитаете значение, а затем вызовете функцию, значение будет таким же. Сравните это с const(T), что обеспечивает более слабую гарантию того, что этот экземпляр типа не будет изменен, но кто-то может иметь изменяемый доступ к нему в другом месте, поэтому, если вы читаете значение и затем вызываете функцию, вы не можете принять значение будет таким же.

В общем, immutable(T) != T. Однако существуют определенные ситуации, когда они неявно конвертируются друг в друга. Если T является типом, который, как говорят, не имеет "изменяемой косвенности", например. То есть, если я передам функции immutable(int), они получат копию - эта функция не сможет изменить переданное мной значение, так как оно копируется - если система типов не допустит этого , это было бы просто раздражающим без каких-либо дополнительных гарантий, поэтому система типов D позволяет это. Однако, если я передам неизменяемый (int *), то может быть изменен вызывающей функцией . В случае структур, если у какого-либо члена есть изменяемая косвенность, то говорят, что структура также имеет его.

Таким образом, чтобы отвлечься от теории и вернуться к более практическим вопросам, совершенно неверно, что неизменные ценности должны быть известны во время компиляции, и что нет хорошего способа их создания. Однако единственная мутация может происходить внутри конструктора. Для простых скалярных типов это довольно очевидно:

immutable(int) i = rand();

Но как насчет чего-то вроде объекта? Ну, для построения типа T мы используем

auto t = new T();

поэтому для построения типа неизменяемого (T) мы используем

auto t = new immutable(T)();

вот более полный маленький пример

class Useless
{
    int i;

    this(int i)
    {
        this.i = i;
    }
}

int main(string[] args)
{
    auto o = new immutable(Useless)(cast(int) args.length);
    //o.i = 17;  error
    return o.i;  // fine
}

Как видите, мутация может происходить внутри конструктора. Вы можете читать переменные-члены, но не можете их записывать (неизменяемый является транзитивным; то есть каждый член (и каждый член-члены) становится неизменным, если это делает родитель. Вы можете вызывать методы, только если они помечены как const.

Я прошу прощения за бессвязные сообщения, но вижу, что многие люди смущены этой темой.

3 голосов
/ 18 мая 2011

Ответ fwend в основном мертвый, но если вы ищете что-то немного менее многословное, вы всегда можете сделать миксин для его автоматизации.Непроверенный код ниже, чтобы дать общее представление:

string readOnly(string typeName, string varName) {
    // Create a private variable that prepends an _ to the name and a 
    // public accessor named name.  
    return "private " ~ typeName ~ " _" ~ varName ~ ";\n" ~
           "public " ~ typeName ~ 
           "varName() @property { return _" ~ varName ~ ";\n";
}

Использование:

class Foo {
    mixin(readOnly("int", "num"));

    void incNum() {
        _num++;
    }
}
2 голосов
/ 18 мая 2011

Я бы объявил поле как личное, а затем использовал бы метод доступа get, чтобы прочитать его

...