2011-05-17 66 views
7

根据我对D的了解,在变量上使用immutable关键字时,变量的值必须在编译时已知,而C#的readonly不需要,而readonly字段可以在类构造函数中分配使用非静态值。这可能在D吗?D中C#`readonly`关键字的等价物吗?

+0

我相信我的答案与当前版本的D不兼容。请看@Raphaël的答案。 – ChaosPandion 2011-05-17 23:13:01

+0

不可变不需要在编译时知道,在运行期间没有任何好的方法来创建它们,没有投射 – 2011-05-17 23:24:27

回答

6

由于存在似乎有些混乱(来自原来的问题,并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时才能调用方法。

对于这个题外话,我很抱歉,但是我看到很多人似乎对这个主题感到困惑。

+0

谢谢您的深入解释。这清除了我在D中关于这些关键字的很多混淆(我认为我正在混合使用D 1.0和2.0语义)。 – 2011-05-18 21:25:45

2

我宣布现场为私有,然后用get访问读它

+0

这是D2中的最佳解决方案 – dsimcha 2011-05-17 21:44:56

3

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

在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 
} 
+0

这实质上是只读行为在C#中。 – ChaosPandion 2011-05-17 22:09:32

相关问题