相当于 D 中的 C# “只读”关键字

本文关键字:只读 关键字 中的 相当于 | 更新日期: 2023-09-27 17:56:38

根据我在阅读 D 时的理解,当对变量使用 immutable 关键字时,变量的值必须在编译时知道,而 C# 的readonly不必知道,并且可以使用非静态值在类构造函数中分配readonly字段。这在 D 中可能吗?

相当于 D 中的 C# “只读”关键字

在 D2 中,const 成员只能在构造函数中初始化(或直接在类声明中初始化,但不能同时初始化):

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
}
由于似乎有一些

关于不可变的混淆(来自原始问题和he_the_great的评论),我想我会添加一个旁白。

当你说immutable int i = 42时,你是说我不会被修改,而不是说它在编译时是已知的值。 immutable实际上是一个类型修饰符,并创建一个新类型。 immutable Timmutable(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 时,才能调用方法。

对于偏离主题的漫无边际,我深表歉意,但我看到很多人似乎对这个话题感到困惑。

fwend的答案基本上是死的,但是如果你正在寻找一些不那么冗长的东西,你总是可以做一个mixin来自动化它。 下面未经测试的代码给出了大致的想法:

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

我会将字段声明为私有字段,然后使用 get 访问器读取它