有没有办法用 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;
}
通过使用 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;
}