常量不可变的BigInt和range.join在D中

常量不可变的BigInt和range.join在D中,d,D,我正在学习D,我一直在使用火卫一中定义的越来越多的功能和工具。我遇到了两个在参数为常量或不可变时不起作用的函数 BigInt i = "42", j = "42"; writeln(i + j); // This works, except when I add a const/immutable qualifier to i and j // When const: main.d(23): Error: incompatible types for ((i) + (j)): 'const(Bi

我正在学习D,我一直在使用火卫一中定义的越来越多的功能和工具。我遇到了两个在参数为常量或不可变时不起作用的函数

BigInt i = "42", j = "42";
writeln(i + j);
// This works, except when I add a const/immutable qualifier to i and j
// When const: main.d(23): Error: incompatible types for ((i) + (j)): 'const(BigInt)' and 'const(BigInt)'
// When immutable: main.d(23): Error: incompatible types for ((i) + (j)): 'immutable(BigInt)' and 'immutable(BigInt)'
std.array.join函数也会发生同样的情况

int[] arr1 = [1, 2, 3, 4];
int[] arr2 = [5, 6];
writeln(join([arr1, arr2]));
// Again, the const and immutable errors are almost identical
// main.d(28): Error: template std.array.join(RoR, R)(RoR ror, R sep) if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isInputRange!R && is(Unqual!(ElementType!(ElementType!RoR)) == Unqual!(ElementType!R))) cannot deduce template function from argument types !()(const(int[])[])
这让我很惊讶。我有C++背景,所以我通常到处写const,但是我似乎不能在D.< /P>中做它。
作为一个D“用户”,我认为这是一个bug。有人能解释一下为什么这不是一个bug,以及我应该如何用常量/不可变数据调用这些函数吗?谢谢。

首先,我应该说D的
常量与C++的
常量非常不同。与C++一样,理想的是尽可能多地标记它,但是与C++不同,在D.< /P>中标记“<代码> const <代码>的后果是严重的。
代码> const 是传递的,因此它影响整个类型,而不仅仅是顶层,并且与C++不同,不能通过将其转换或使用<代码>可更改的< /代码>来改变它(它是未定义的行为,如果试图从一个对象中抛出<代码> const <代码>,然后将其进行变异,将导致严重错误)。这两件事的结果是,在很多地方,你不能在D中使用
const
,而不能做某些事情

D的
const
提供了真实可靠的保证,保证您不能通过该引用以任何方式、形状或形式对对象进行变异,而C++的
const
只是让您不能意外地对
const
进行变异,但您可以轻松地抛弃
const
并对对象进行变异(定义行为),或者可以通过<代码> const 函数内部更改对象,这是由于易变的。C++中也不需要从“代码> const <代码>函数返回一个类的内部引用,即使没有转换或代码>可变的< /代码>。(例如,从
const
函数返回
vector
vector
不能变异,但它所指的一切都可以变异)这些在D中都是不可能的,因为D保证完全可传递的
const
,并且提供这些保证使得任何需要从
const
中获取可变内容的情况都无法工作,除非您创建一个全新的副本

您可能应该仔细阅读以下问题的答案:

这样,如果你在D中的所有东西上都是“代码> const <代码>,你会发现有些东西是行不通的。使用C++代码> const 尽可能多的是因为C++中的相同原因,但是代价要高得多,所以你必须对你用“代码> const ”标记的东西进行更严格的限制。

现在,关于您的具体问题。
BigInt
应该与
const
immutable
一起使用,但目前没有。在这个问题上存在很多问题。我相信很多问题都源于
BigInt
内部使用,这与
const
immum的使用不太好表
。幸运的是,目前至少有一个解决了一些问题的解决方案,因此我预计
BigInt
将在不久的将来使用
const
immutable
,但目前,您不能

至于
join
,您的示例编译得很好,所以您的代码复制错误。您的示例中没有
const
。也许您的意思是

const int[] arr1 = [1, 2, 3, 4];
const int[] arr2 = [5, 6];
writeln(join([arr1, arr2]));

这不会编译。这是因为您没有将有效的范围传递给
join
。在这种情况下,传递给
join
的类型将是
const(int[])[]
。外部数组是可变的,所以这很好,但是内部数组(您试图连接在一起的范围)是
const
,并且
const
不能是有效的范围,这是因为
popFront
不起作用。对于要成为有效输入范围的内容,必须为其编译此代码(这是从标准范围isInputRange的内部获取的)

const(int[])
不能与
popFront
一起使用,因为
isInputRange
需要

const int[] arr = [1, 2, 3];
arr.popFront();
不会编译,因此
isInputRange
false
,而
join
不会使用它编译

现在,幸运的是,数组有点特殊,因为编译器理解它们,所以编译器知道在切片时将
const(int[])
转换为
const(int)[]
是完全合法的。也就是说,它知道给你一个尾常量切片不会影响原始数组(因为结果是一个新数组,当数组之间共享元素时,它们都是
const
,所以它们仍然不能变异)。因此
arr[]
的类型将是
const(int)[/code>而不是
const(int[])
,而
[arr1[],arr2[]
的类型是
const(int)[]
,它将与
join
一起使用

const int[] arr1 = [1, 2, 3, 4];
const int[] arr2 = [5, 6];
writeln(join([arr1[], arr2[]]));
您的代码也可以正常工作。但是,这只是因为您使用的是数组。如果您处理的是用户定义的范围,那么在创建其中一个
常量的那一刻,您就会陷入困境。此代码无法编译

const arr1 = filter!"true"([1, 2, 3, 4]);
const arr2 = filter!"true"([5, 6]);
writeln(join([arr1[], arr2[]]));
这是因为编译器不知道它可以安全地从ser定义的类型中获取tail const片段。它需要知道它可以将
const MyRange!E
转换为
MyRange!(const E)
并具有正确的语义。它无法知道这一点,因为这是两个不同的模板实例化,它们可能具有完全不同的内部结构。编写
MyRange
的程序员必须能够编写
opSlice
,以便返回
MyRange(const)
当类型为
const MyRange!E
const MyRange!(const E)
时,这就是ac
const arr1 = filter!"true"([1, 2, 3, 4]);
const arr2 = filter!"true"([5, 6]);
writeln(join([arr1[], arr2[]]));