【发布时间】:2011-04-21 05:46:25
【问题描述】:
在 C++ 中。我可以将大多数东西声明为 const,例如:
变量:const int i=5;
Scala 有 val i=5,但是这只会阻止重新分配,而不是更改对象,如下例所示:
C++:
const int i[]={1,2,3,4};
i[2]=5; //error
斯卡拉:val a=Array(1,2,3,4)
a(2)=5 //a is now Array(1, 2, 5, 4)
成员函数会变得更糟:
C++:
class Foo {
int i;
int iPlusFive() const {return i+5;}
int incrementI(){ return ++i; }
}
我可以肯定,调用 iPlusFive 不会更改对象,并且我不会意外地在 const 对象上调用 incrementI。
在集合方面,C++ 继续使用 const 集合保持 const 正确性:只需将向量声明为 const 即可,您无法更改它。将 non-const vector<Int> 分配给 const vector<Int>,编译器不会复制任何内容,并且会阻止您更改 now const 集合中的任何内容。
Scala 有 scala.collection.mutable.whatever 和 scala.collection.immutable.whatever,您不能只将可变集合转换为不可变集合,此外,您仍然可以使用它们的非常量成员更改收集的对象功能。
为什么具有非常棒的类型系统的 scala 没有任何可以与 C++ const-keyword 相媲美的东西?
编辑:
Margus 建议使用import scala.collection.mutable。
我的解决方案是使用
import scala.collection.mutable.HashMap
import scala.collection.immutable.{HashMap => ConstHashMap}
这将使可变 HashMap 可用作 HashMap 和不可变 als ConstHashMap,但是我仍然更喜欢 C++ 方法。
【问题讨论】:
-
我将此添加为评论,因为它并不是真正的答案。我能想出的唯一答案是它不是“设计使然”。事实上,很少有编程语言具有与 C++ 相同的 const 语义。有些根本没有,其他的像 Java/C# 有一个有限的形式(类似于 scala),它阻止代码重新分配给 reference,但不能保证 referred 对象(原始类型在某些情况下的处理方式不同,可以设为常量)。
-
对刚刚创建的、有意使用而没有突变的东西进行突变基本上是错误的,并且不受静态编译器检查的影响。但是把它传递给一个需要“非变异”接口的方法——那里不可能有变异(即使是错误的)。所以仅仅从适当的接口继承就可以从根本上解决问题。
-
C++ 本身并不能阻止我更改所指的内容。写
const int i(5); const int * cip(&i); int * ip(const_cast<int *>(cip)); *ip = 6;之类的东西是未定义的行为,但这并不意味着任何事情都会阻止你。 -
如果你还没有读过james-iry.blogspot.com/2010/07/when-constants-vary.html,C++ 中 const 的实用性和保证有一些严重的限制。
-
那篇博客文章很好地解释了
const的实际效果与假设const== 不变的人们的期望。如果您认为函数的签名是定义调用者赋予被调用者期望和更改的权利的合同,那么突然const的行为(以及隐式添加 cv-qualification) 非常有意义。在另一个世界中,const表示常量并承诺被调用者参数不会改变,那么隐式转换将是 remove cv-qualification。