有没有办法用 Dlang 一次分配多个变量?

Is there any way to assign multiple variable at once with Dlang?

通过使用 Ruby,我们可以做到这一点。

s = "split by space"
A,B,C = s.split(" ").map(&:to_i)

使用D-lang,编译错误

string s = "split by space";
int A,B,C = s.split(" ").map!(x => x.to!int);

不,没有办法做到这一点。关于可能向语言添加元组支持的讨论断断续续,这样你就可以像

int a;
int b;
string c;
(a, b, c) = foo();

也许有一天会发生,但现在不可能。最接近的是使用 std.typecons.Tuple/tuple 这样的东西,这样你就可以做

Tuple!(int, int, string) foo() { return tuple(42, 29, "hello"); }
Tuple!(int, int, string) result = foo();

或更有可能

auto foo() { return tuple(42, 29, "hello"); }
auto result = foo();

Tuple 最终只是一个结构,你不能神奇地将它从另一端拆分出来。您必须通过 result[0]result[1] 等索引访问其成员,或者如果您使用名称声明 Tuple - 例如Tuple!(int, "x", int, "y", string, "str") - 然后您可以按名称访问成员 - 例如result.x。因此,Tuple/tuple 允许您 return 多个值而无需为此显式声明结构类型,但它仍在为此创建结构类型,同时它允许您轻松将值打包到 return,它不允许您在另一端自动解包它们。这将需要某种我们没有的编译器支持。

然而,即使我们在语言中有更好的元组支持,所以像

(a, b, c) = foo();

有效,我怀疑您尝试做的事情是否有效,因为 map 特别是 return 是一个范围。因此,它是一个具有成员函数的对象,而不是任何类型的要拆分的元组。它恰好表示可以使用正确的函数调用集提取的值列表。并且它具有的值的数量在编译时是未知的,因此即使您假设编译器足够了解范围原语以从中为您获取列表,它也不能保证在编译时有足够的值可以放入您要分配给的变量中,更不用说恰好有那么多值了。因此,虽然使类似的东西工作并非不可能(例如,如果范围内没有足够的值,它会在编译时抛出 Error),但如果实现了,我会感到惊讶. D 是一种静态类型的语言,它会有效地使其成为动态的一部分,所以它在语言中是非常不合时宜的。 Ruby 是一种动态语言,因此它是一种非常不同的野兽。

无论如何,对元组的任何改进都将是对语言的改进,并且必须通过 DIP process 并获得批准,而这样的事情还没有发生。

Jonathan 大部分是对的,但实际上有一种方法可以将 tuple 拆分为 它的组成部分,尽管比 Ruby 更冗长,而且没有任何方便的 类型推断:

import std.meta : AliasSeq;
import std.typecons : tuple;

auto foo() { return tuple(42, 29, "hello"); }

unittest {
   int a, b;
   string c;
   AliasSeq!(a, b, c) = foo(); // Look ma, magic!
   assert(a == 42);
   assert(b == 29);
   assert(c == "hello");
}

虽然没有像您的示例那样使用范围执行此操作的内置方法,但它 可以在库中实现:

import std.meta : AliasSeq, Repeat;
import std.typecons : Tuple, tuple;
import std.algorithm : map;
import std.conv : to;
import std.string : split;
import std.range : isInputRange, ElementType;

unittest {
   string s = "1 2 3";
   int A,B,C;
   AliasSeq!(A,B,C) = s.split(" ").map!(x => x.to!int).tuplify!3;
   assert(A == 1);
   assert(B == 2);
   assert(C == 3);
}

auto tuplify(size_t n, R)(R r) if (isInputRange!R) {
   Tuple!(Repeat!(n, ElementType!R)) result;

   static foreach (i; 0..n) {
      result[i] = r.front;
      r.popFront();
   }
   assert(r.empty);

   return result;
}