简体   繁体   English

D中C#`readonly`关键字的等价物?

[英]Equivalent of C# `readonly` keyword in D?

From what I understand while reading up on D, when using the immutable keyword on a variable, the value of the variable must be known at compile time, while C#'s readonly need not be, and readonly fields can be assigned in a class constructor using non-static values. 根据我在阅读D时的理解,当在变量上使用immutable关键字时,变量的值必须在编译时知道,而C#的readonly不需要,并且readonly字段可以在类构造函数中使用non分配 - 静态价值观。 Is this possible in D? 这可能在D?

In D2, const member can only be initialized inside the constructor (or directly in the class declaration, but not both): 在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
}

As there appears to be some confusion (from both the original question, and he_the_great's comment) regarding immutable, I thought I'd add an aside. 由于关于不可变的问题似乎存在一些混淆(来自原始问题和he_the_great的评论),我想我会补充一点。

When you say immutable int i = 42 , you are saying that i will not be modified, not that it the value is known at compile time. 当你说immutable int i = 42 ,你说我不会被修改,而不是在编译时知道它的值。 immutable is actually a type modifier, and creates a new type. immutable实际上是一个类型修饰符,并创建一个新类型。 immutable T is a short-hand for immutable(T) . immutable Timmutable(T)的简写。 immutable(T) creates a T that can never be mutated, that is, if you read the value, then call a function, the value will be the same. immutable(T)创建一个永远不会变异的T,也就是说,如果你读取了值,然后调用一个函数,那么值就是相同的。 Compare this to const(T) which provides the weaker guarantee that this instance of the type will not be modified, but someone may have mutable access to it else where, so if you read the value and then call a function, you cannot assume the value will be the same. 将此与const(T)进行比较,它提供了较弱的保证,即该类型的实例不会被修改,但有人可能对其他地方进行了可变访问,因此,如果您读取该值然后调用函数,则不能假设价值会是一样的。

In general, immutable(T) != T . 通常, immutable(T) != T However there are certain situations where they are implicitly convertible to one another. 然而,在某些情况下,它们可以隐含地相互转换。 If T is a type that is said to have no "mutable indirection", for instance. 例如,如果T是一种被认为没有“可变间接”的类型。 That is to say, if I pass a function an immutable(int) , they receive a copy -- there is no way that that function can modify the value I passed, as it is copied -- if the type system didn't allow that, it would just be annoying with no added guarantees, so the D type system allows it. 也就是说,如果我传递一个函数一个immutable(int) ,它们会收到一个副本 - 如果类型系统不允许,那么该函数无法修改我传递的值,因为它被复制了如果没有额外的保证就会很烦人,所以D型系统允许它。 However, if I pass an immutable(int*), that can be changed by the calling function. 但是,如果我传递一个immutable(int *),那么可以通过调用函数进行更改。 In the case of structs, if any member has mutable indirection then the struct is said to have it as well. 在结构的情况下,如果任何成员具有可变间接,那么结构也被称为具有它。

So to turn away from theory and back to more practical matters, it's not true at all that immutable values have to be known at compile time, and that there's no good way to create them. 因此,为了摆脱理论并回到更实际的问题,根本不可能在编译时知道不可变值,并且没有好的方法来创建它们。 However, the only mutation can occur inside the constructor. 但是,唯一的突变可能发生在构造函数内部。 For simple scalar types, this is pretty obvious: 对于简单的标量类型,这很明显:

immutable(int) i = rand();

But what about something like an object? 但是像对象一样呢? Well, to construct a type T we use 好吧,构建我们使用的类型T.

auto t = new T();

so to construct the type immutable(T) we use 所以要构造我们使用的类型immutable(T)

auto t = new immutable(T)();

here's a more complete little example 这是一个更完整的小例子

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
}

As you can see, mutation can occur inside the constructor. 如您所见,构造函数内部可能发生变异。 You can read member variables, but cannot write them (immutable is transitive; that is, every member (and every member of members) becomes immutable if the parent does. You can only call methods if they're marked as const . 您可以读取成员变量,但不能写它们(不可变是传递性的;也就是说,如果父进程,每个成员(以及成员的每个成员)都变为不可变。只有当它们被标记为const才能调用方法。

I apologise for the off-topic rambling, but I see that a lot of people appear to be confused regarding this topic. 我为偏离话题的漫无边际道歉,但我看到很多人似乎对这个话题感到困惑。

fwend's answer is basically dead-on, but if you're looking for something a little less verbose, you could always make a mixin to automate it. fwend的答案基本上是死的,但如果你正在寻找一些不那么冗长的东西,你可以随时制作一个mixin来自动化它。 Untested code below to give the general idea: 下面未经测试的代码给出了一般的想法:

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

Usage: 用法:

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

    void incNum() {
        _num++;
    }
}

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM