简体   繁体   English

为D中的const和非const结构提供@property

[英]Provide @property for const and non-const structures in D

I define a simple struct this way: 我用这种方式定义一个简单的结构:

struct Person{
    private string _name;

    @property ref string name() { return _name; }
}

The @property annotation is really cool, but I don't know how should I use it properly. @property注释非常酷,但我不知道应该如何正确使用它。

The above is quite ok, but I cannot pass a Person to a function requiring in Person for instance: 以上是相当不错的,但是我无法将Person传递给需要in Person的函数,例如:

void fun(in Person p) { ... } 

To avoid copying Person I have to declare the parameter with ref , though I don't modify it. 为了避免复制Person我必须使用ref声明参数,尽管我不修改它。

So how to combine the property syntax with const-correctness? 那么如何将属性语法与const-correctness结合起来呢?


edit: To follow up, can the same apply to looping? 编辑:要跟进,可以同样适用于循环吗?

void fun(in Person[] people) {
    foreach(Person p; people) { ... }
}

now I don't want to copy person, but I can't use ref Person since it's const. 现在我不想复制人,但我不能使用ref Person因为它是const。 So I have to write ref const(Person) p in the loop which becomes loong. 所以我必须在循环中编写ref const(Person) p ,它变成了loong。

Normally, what you'd do would be 通常,你会做什么

@property string name() const { return _name; }
@property void name(string value) { _name = value; }

and you wouldn't bother with ref (certainly, for a string , there isn't much point). 你不会打扰ref (当然,对于一个string ,没有太多意义)。 For more complex types that you want to avoid copying, you can return by const ref , eg 对于要避免复制的更复杂类型,可以通过const ref返回,例如

@property ref const(Foo) foo() const { return _foo; }
@property void foo(Foo value) { _foo = value; }

You could overload the setter so that it accepted ref Foo in addition to Foo , but there isn't much point, since you'd be copying the passed in Foo to assign it to _foo anyway. 可以重载二传手,使其接受ref Foo除了Foo ,但没有多大意义,因为你会复制传递Foo将它指定_foo反正。

And if you really want to, you can return by ref from the getter and overload it, eg 如果你真的想要,你可以通过ref从getter返回并重载它,例如

@property ref const(Foo) foo() const { return _foo; }
@property ref Foo foo() { _foo; }

in which case the non-const overload can be used as a setter, but if you're going to do that, why bother with a property? 在这种情况下,非const重载可以用作setter,但是如果你要这样做,为什么还要使用属性呢? At that point, you might as well just make the member variable public, because the property isn't protecting it at all. 此时,您可能只需将成员变量设为public,因为该属性根本不保护它。 By returning non-const ref , you've lost control over how the member variable is set and have effectively exposed it as a public member variable except that you have the extra plumbing of the function around it. 通过返回非const ref ,您已经失去了对成员变量设置方式的控制,并且已经有效地将其作为公共成员变量公开,除了您有额外的函数管道。 The only advantages that it gives you are that you can do something before returning and that the type's invariant (if any) will be called when the property is called (whereas it won't with a public member variable), but because the variable can be set without you're control at that point, those benefits are of questionable value in comparison to the simplicity of simply making the member variable public. 它给你的唯一好处是你可以在返回之前做一些事情,并且在调用属性时将调用类型的不变量(如果有的话)(而不会使用公共成员变量),但因为变量可以在没有你控制的情况下设置,与简单地将成员变量公开的简单性相比,这些好处具有可疑的价值。

So, in general, the first example is the way to go, and once in a while, the second is better, but it's arguably pointless to go with the third example. 所以,一般来说,第一个例子是要走的路,偶尔,第二个例子是更好的,但是与第三个例子相比,它可能毫无意义。

EDIT: 编辑:

As Kozzi11 points out , you can implement the 3rd example as 正如Kozzi11指出的那样 ,你可以实现第三个例子

@property auto ref foo() inout { return _foo; }

or 要么

@property ref inout(Foo) foo() inout { return _foo; }

instead of having two functions, but my point about it not really being much better than a public member variable still applies. 而不是有两个函数,但我对它的观点并不比公共成员变量更好。

EDIT 2: With regards to your edit to the question... 编辑2:关于你对问题的编辑...

If you want to avoid copying in the loop, you're going to have to be explicit with the type. 如果你想避免在循环中复制,你必须明确表示类型。

foreach(p; people) { ... }

will work, but it will copy each individual Person as it iterates over people , whereas 会工作,但它会复制每个Person因为它迭代people

foreach(ref Person p; people) { ...}

or 要么

foreach(ref const(Person) p; people) { ...}

will avoid copying each Person . 将避免复制每个Person

What about this: 那这个呢:

import std.stdio;

void someFun(in Person person) {
    writeln(person.name);
}

struct Person {
    private string _name;
    @property auto ref name() inout { return _name; }
}

void main(string[] args)
{
    auto person = Person("Osoba Nova");
    someFun(person);
    stdin.readln;
}

EDIT: for loop you can ommit type 编辑:for循环你可以省略类型

void fun(in Person[] people) {
    foreach (p; people) {
        writeln(p.name);
    }
}

a property function is just a function, so you can overload it. 属性函数只是一个函数,所以你可以重载它。

@property ref const(string) name() const { return name_; }
@property ref string name() { return name_; }

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

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