从 D 中的结构方法通过引用返回
Returning by reference from struct method in D
我正在从 C++ 开始我的 D 之旅。在 C++ 中,通过引用或值传递是非常明确的,但在 D 中,它似乎在结构和 classes 之间有所不同。
我的问题是如何通过引用强制 return?
我有一个简单的 XmlNode class 用于构建 Xml 树(这是我的 C++ 代码的提升):
import std.stdio;
struct XmlNode
{
string _name;
string _data;
XmlNode[] _children;
this(string name, string data="")
{
_name = name;
_data = data;
}
//Trying to return a reference to the added Node
ref XmlNode addChild(string name,string data = "")
{
_children ~= XmlNode(name,data);
return _children[$-1];
}
string toString(bool bPlain = true, string indent = "")
{
//Omitted for brevity
}
}
这里是测试代码:
int main()
{
auto root = XmlNode("root");
//Chained call
root.addChild("Level 1").addChild("Level 2","42");
//Call in two parts
auto n = root.addChild("Level 1");
n.addChild("Level 2","101"); //n seems to be a copy not a reference
//Chained call
root.addChild("Level 1").addChild("Level 2","999");
writeln(root.toString(false));
return 0;
}
给出以下输出:
root
Level 1
Level 2
42
Level 1
Level 1
Level 2
999
如您所见,'chained' 对 addChild()
的使用达到了预期效果。但是,如果我尝试将其分成两个单独的调用,则只有第一个有效,而第二个似乎对第一个的副本进行操作,而不是引用。我乐观地向 addChild() 签名添加了一个 ref
限定符,但这似乎没有帮助。
一如既往,如果有任何建议,我将不胜感激(使用 DMD / Visual D / Visual Studio / Windows 10)。
auto n = root.addChild("Level 1");
这里,虽然 addChild
returns 一个引用,它被分配给一个变量,因此被取消引用和复制。相反,您可能想要:
auto n = &root.addChild("Level 1");
请注意,D 没有引用变量,就像在 C++ 中一样。变量只能是指针(尽管可以编写具有 reference-like 语义的包装器模板)。
另请注意,在 XmlNode
的当前设计中,返回的引用仅在下一次修改 _children
之前有效(因为这可能会导致重新分配,从而将内容移动到另一个地址,使任何现存的参考资料都已过时)。这是一种常见的 footgun,可以通过存储 XmlNode
的引用(或使其成为引用类型,即 class)来避免,代价是额外的取消引用和分配。
我正在从 C++ 开始我的 D 之旅。在 C++ 中,通过引用或值传递是非常明确的,但在 D 中,它似乎在结构和 classes 之间有所不同。
我的问题是如何通过引用强制 return?
我有一个简单的 XmlNode class 用于构建 Xml 树(这是我的 C++ 代码的提升):
import std.stdio;
struct XmlNode
{
string _name;
string _data;
XmlNode[] _children;
this(string name, string data="")
{
_name = name;
_data = data;
}
//Trying to return a reference to the added Node
ref XmlNode addChild(string name,string data = "")
{
_children ~= XmlNode(name,data);
return _children[$-1];
}
string toString(bool bPlain = true, string indent = "")
{
//Omitted for brevity
}
}
这里是测试代码:
int main()
{
auto root = XmlNode("root");
//Chained call
root.addChild("Level 1").addChild("Level 2","42");
//Call in two parts
auto n = root.addChild("Level 1");
n.addChild("Level 2","101"); //n seems to be a copy not a reference
//Chained call
root.addChild("Level 1").addChild("Level 2","999");
writeln(root.toString(false));
return 0;
}
给出以下输出:
root
Level 1
Level 2
42
Level 1
Level 1
Level 2
999
如您所见,'chained' 对 addChild()
的使用达到了预期效果。但是,如果我尝试将其分成两个单独的调用,则只有第一个有效,而第二个似乎对第一个的副本进行操作,而不是引用。我乐观地向 addChild() 签名添加了一个 ref
限定符,但这似乎没有帮助。
一如既往,如果有任何建议,我将不胜感激(使用 DMD / Visual D / Visual Studio / Windows 10)。
auto n = root.addChild("Level 1");
这里,虽然 addChild
returns 一个引用,它被分配给一个变量,因此被取消引用和复制。相反,您可能想要:
auto n = &root.addChild("Level 1");
请注意,D 没有引用变量,就像在 C++ 中一样。变量只能是指针(尽管可以编写具有 reference-like 语义的包装器模板)。
另请注意,在 XmlNode
的当前设计中,返回的引用仅在下一次修改 _children
之前有效(因为这可能会导致重新分配,从而将内容移动到另一个地址,使任何现存的参考资料都已过时)。这是一种常见的 footgun,可以通过存储 XmlNode
的引用(或使其成为引用类型,即 class)来避免,代价是额外的取消引用和分配。