我用这种方式定义一个简单的结构:
struct Person{
private string _name;
@property ref string name() { return _name; }
}
@property
注释非常酷,但我不知道应该如何正确使用它。
以上情况还可以,但我无法将Person
传递给需要in Person
的函数,例如:
void fun(in Person p) { ... }
为避免复制Person
,我必须使用ref
声明参数,但我不会修改它。
那么如何将属性语法与const-correctness结合起来呢?
编辑: 要跟进,这同样适用于循环吗?
void fun(in Person[] people) {
foreach(Person p; people) { ... }
}
现在我不想复制人,但我不能使用ref Person
,因为它是常量。所以我必须在循环中写ref const(Person) p
来成为loong。
答案 0 :(得分:5)
通常,你要做的是
@property string name() const { return _name; }
@property void name(string value) { _name = value; }
你不会打扰ref
(当然,对于string
,没有多大意义)。对于要避免复制的更复杂类型,可以通过const ref
返回,例如
@property ref const(Foo) foo() const { return _foo; }
@property void foo(Foo value) { _foo = value; }
你可以重载setter,使其除了ref Foo
之外还接受Foo
,但没有多大意义,因为你要复制传入的Foo
无论如何都要将其分配给_foo
。
如果真的想要,你可以通过ref
从getter返回并重载它,例如。
@property ref const(Foo) foo() const { return _foo; }
@property ref Foo foo() { _foo; }
在这种情况下,非const重载可以用作setter,但是如果你要这样做,为什么还要使用属性呢?此时,您可能只需将成员变量设为public,因为该属性根本不保护它。通过返回非const ref
,你已经失去了对成员变量设置方式的控制,并且已经有效地将其作为公共成员变量公开,除了你有额外的函数管道。它给你的唯一好处是你可以在返回之前做一些事情,并且在调用属性时将调用类型的不变量(如果有的话)(而不会使用公共成员变量),但因为变量可以在没有你控制的情况下进行设置,与简单地将成员变量公开的简单性相比,这些好处具有可疑价值。
所以,一般来说,第一个例子是要走的路,偶尔,第二个例子会更好,但是第三个例子可能毫无意义。
修改强>
作为Kozzi11 points out,您可以将第三个示例实现为
@property auto ref foo() inout { return _foo; }
或
@property ref inout(Foo) foo() inout { return _foo; }
而不是有两个函数,但我对它的看法并不比公共成员变量好得多。
编辑2:关于您对问题的修改......
如果你想避免在循环中复制,那么你必须明确这个类型。
foreach(p; people) { ... }
可以使用,但会在Person
上迭代时复制每个人people
,而
foreach(ref Person p; people) { ...}
或
foreach(ref const(Person) p; people) { ...}
将避免复制每个Person
。
答案 1 :(得分:3)
这个怎么样:
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;
}
编辑:for循环你可以省略类型
void fun(in Person[] people) {
foreach (p; people) {
writeln(p.name);
}
}
答案 2 :(得分:1)
属性函数只是一个函数,所以你可以重载它。
@property ref const(string) name() const { return name_; }
@property ref string name() { return name_; }