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

时间:2017-11-01 01:19:07

标签: d

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

// You might need org.springframework.ws:spring-ws-support in order to
// have HttpsUrlConnectionMessageSender
public final class BasicAuthHttpsConnectionMessageSender extends HttpsUrlConnectionMessageSender {
  private String b64Creds;

  public BasicAuthHttpsConnectionMessageSender(String username, String password) {
    b64Creds = Base64.getUrlEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));
  }

  @Override
  protected void prepareConnection(HttpURLConnection connection) throws IOException {
    connection.setRequestProperty(HttpHeaders.AUTHORIZATION, String.format("Basic %s", b64Creds));
    super.prepareConnection(connection);
  }
}

使用D-lang时,编译错误。

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

2 个答案:

答案 0 :(得分:4)

乔纳森大多是对的,但事实上有一种方法可以将tuple分成其组成部分,虽然比Ruby更冗长,并且没有任何方便的类型推断:

import std.traits : 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.traits : AliasSeq;
import std.meta : 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;
}

答案 1 :(得分:3)

不,没有办法做到这一点。关于可能为语言添加元组支持以及类似

之类的内容一直存在争议
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允许您返回多个值而不显式声明结构类型,但它仍然只为此创建结构类型,并且它允许您轻松地将值打包到返回,它不允许您在另一端自动解压缩它们。这需要我们没有的某种编译器支持。

但是,即使我们在语言中有更好的元组支持,以便像

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

工作,我怀疑你尝试做什么会起作用,因为map专门返回一个范围。所以,它是一个具有成员函数的对象,而不是任何类型的元组被拆分。它恰好表示可以使用正确的函数调用集提取的值列表。并且它在编译时不知道它的值的数量,所以即使你假设编译器很好地理解了范围原语以便为你获取它们的列表,它也不能保证在编译时它有足够的值放入你想要分配的变量中,更不用说确实存在那么多的值了。所以,虽然不可能做出像这样的工作(例如,如果它在编译时抛出Error,如果范围内没有足够的值),我会感到惊讶,如果这是实现的。 D是一种静态类型的语言,它实际上会使它成为动态的一部分,因此它在语言中是非常不合适的。 Ruby是一种动态语言,因此它是一种非常不同的野兽。

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