Properties 为D中的常量和非常量结构提供@property

Properties 为D中的常量和非常量结构提供@property,properties,constants,d,Properties,Constants,D,我这样定义一个简单的结构: struct Person{ private string _name; @property ref string name() { return _name; } } @property注释真的很酷,但我不知道该如何正确使用它 上面的内容很好,但我无法将个人传递给需要亲自的函数,例如: void fun(in Person p) { ... } 为了避免复制Person,我必须用ref声明参数,尽管我没有修改它 那么,如何将属性语法与常量正确

我这样定义一个简单的结构:

struct Person{
    private string _name;

    @property ref string name() { return _name; }
}
@property
注释真的很酷,但我不知道该如何正确使用它

上面的内容很好,但我无法将
个人
传递给需要
亲自
的函数,例如:

void fun(in Person p) { ... } 
为了避免复制
Person
,我必须用
ref
声明参数,尽管我没有修改它

那么,如何将属性语法与常量正确性结合起来呢


编辑: 接下来,同样的情况是否也适用于循环

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

现在我不想复制person,但我不能使用
refperson
,因为它是常量。因此,我必须在循环中写入
ref const(Person)p
,该循环变为龙。

属性函数只是一个函数,因此可以重载它

@property ref const(string) name() const { return name_; }
@property ref string name() { return name_; }
那么这个呢:

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;
}
编辑:对于循环,可以使用ommit类型

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

通常,你会做的是

@property string name() const { return _name; }
@property void name(string value) { _name = value; }
而且您也不会为
ref
而烦恼(当然,对于
字符串
,没有太多意义)。对于要避免复制的更复杂类型,可以通过
const ref
返回,例如

@property ref const(Foo) foo() const { return _foo; }
@property void foo(Foo value) { _foo = value; }
您可以重载setter,使其除了接受
Foo
之外还接受
ref Foo
,但这没有多大意义,因为您将复制传入的
Foo
以将其分配给
\u Foo

如果你真的想,你可以从getter返回
ref
,并重载它,例如

@property ref const(Foo) foo() const { return _foo; }
@property ref Foo foo() { _foo; }
在这种情况下,non-const重载可以用作setter,但是如果要这样做,为什么还要麻烦使用属性呢?此时,您最好将成员变量公开,因为属性根本不保护它。通过返回non-const
ref
,您已经失去了对成员变量设置方式的控制,并且有效地将其作为公共成员变量公开,除非您在其周围有额外的函数管道。它给您带来的唯一好处是,您可以在返回之前执行一些操作,并且在调用属性时将调用类型的不变量(如果有)(而不会使用公共成员变量),但是因为可以在没有您控制的情况下设置变量,与简单地公开成员变量相比,这些好处的价值值得怀疑

所以,总的来说,第一个例子是要走的路,有时第二个更好,但是使用第三个例子毫无意义

编辑:

作为,您可以将第三个示例实现为

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

虽然没有两个函数,但我的观点并不比公共成员变量好多少,仍然适用

编辑2:关于您对问题的编辑

如果要避免在循环中复制,则必须显式使用类型

foreach(p; people) { ... }
将起作用,但它将在迭代
人员时复制每个
人员
,而

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


将避免复制每个

“为了避免复制人,我必须用ref声明参数”。为什么?只需从属性中删除ref。顺便说一句,它应该是return\u name not returnname@Kozzi11但是如果我删除
ref
,那么我将无法分配给
name
。在第一次重载时,您需要它返回
ref const(string)
,并且您需要更改成员变量的名称,否则您将得到无限递归并破坏堆栈。哇,这很好,一个功能,而不是@燃烧器情况下的2个功能。但是 InOuts<代码>怎么工作,我不能把它映射到我的C++知识…?code>inout
将生成该方法的所有可能版本,并使用正确的限定符(const、immutable…)@PAROBAY C++没有什么类似于<代码> IOUT 。
inout
参数(在本例中为
this
指针)被视为
const
,但它保留其类型。其主要优点是使用从函数返回的参数。通过接受
inout
,函数可以接受可变、
const
immutable
参数并返回相同的类型,而如果使用了
const
,则始终会返回
const
。在这种情况下,通过在成员上使用
inout
,它应该以与this指针相同的常量返回
\u name
,而不是像标记为const@Kozzi11从技术上讲,没有生成任何函数。你只有一个声明的。只是调用方将返回类型视为与调用函数的变量相同的常量。当涉及到模板时,您只会得到生成的附加函数,这里不是这种情况。使用
writeln(typeid(typeof(p))要找出typeWell“@property auto ref foo()inout{return\u foo;}”与公共成员的不同之处,您可以返回不同的值,例如“@property auto ref foo()inout{if(bar)return\u foo;else\u foo2;}”乔纳森,谢谢。你的回答很彻底。关于循环,我将选择第三个选项,但我必须承认,我希望从d@已经提出了一些改进建议,例如,但尚未得到批准或实施。
foreach(ref Person p; people) { ...}
foreach(ref const(Person) p; people) { ...}