为什么 scala 没有类似 C++ 的 const 语义?
在C++中。我可以将大多数东西声明为 const,例如:
变量:const int i=5;
Scala 有 val i=5
,但这只会阻止重新分配,而不会更改对象,如以下示例所示:
C++:
const int i[]={1,2,3,4};
i[2]=5; //error
Scala: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; }
}
I can be sure, that calling iPlusFive won't change the object and that I won't accidentally call incrementI on a const object.当谈到集合时,C++ 延续了 const 集合的 const 正确性:只需将向量声明为 const 并且无法更改它。将非常量向量
分配给const向量
,编译器不会复制任何内容,并且会阻止您更改当前const集合中的任何内容。
Scala 有 scala.collection.mutable.whatever 和 scala.collection.immutable.whatever,你不能仅仅将可变集合转换为不可变集合,而且你仍然可以使用它们的非常量成员函数来更改收集的对象。
为什么 scala 拥有一个非常棒的类型系统,却没有任何与 C++ const 关键字相媲美的东西?
编辑: Margus 建议使用import scala.collection.mutable
。 我的解决方案是使用
import scala.collection.mutable.HashMap
import scala.collection.immutable.{HashMap => ConstHashMap}
This will make the mutable HashMap available as HashMap and the immutable als ConstHashMap, however I still like the C++ approach better.In C++. I can declare most things as const, for example:
Variables: const int i=5;
Scala has val i=5
, however this will only prevent reassigning, not changing the object as the following exampe shows:
C++:
const int i[]={1,2,3,4};
i[2]=5; //error
Scala:
val a=Array(1,2,3,4)
a(2)=5 //a is now Array(1, 2, 5, 4)
It gets even worse with member functions:
C++:
class Foo {
int i;
int iPlusFive() const {return i+5;}
int incrementI(){ return ++i; }
}
I can be sure, that calling iPlusFive won't change the object and that I won't accidentally call incrementI on a const object.
When it comes to collections, C++ continues it's const-correct streak with const collections: simply declare your vector as const and you can't change it. Assign a non-const vector<Int>
to a const vector<Int>
and the compiler won't copy anything and will prevent you from changing anything in the now const collection.
Scala has scala.collection.mutable.whatever and scala.collection.immutable.whatever, you can't just convert mutable collections to immutable collections, furthermore you're still allowed to change the collected objects with their non-const member functions.
Why does scala, which has an otherwise really great type-system, not have anything comparable to C++ const-keyword?
Edit:
Margus suggested using import scala.collection.mutable
.
My solution was to use
import scala.collection.mutable.HashMap
import scala.collection.immutable.{HashMap => ConstHashMap}
This will make the mutable HashMap available as HashMap and the immutable als ConstHashMap, however I still like the C++ approach better.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不喜欢 C++ const 逻辑的一点是它与引用有关,而不是与被引用的对象有关。如果我有一个“const T *”,则不能保证持有非常量指针的人不会修改该对象的状态。因此,它无助于避免多线程系统中的竞争条件,也无助于实现持久性容器。
在我看来,拥有不可变类的概念非常有帮助,并且标准库中缺乏不可变容器在任何语言中都是一个错误。由于这些应该表现出可观察的不变性,但出于效率原因可能需要能够改变内部/不可见状态,我认为 const 语法没有什么帮助。
Scala 具有我们需要直接使用或基于其他不可变类的不可变类。这是非常有价值的。额外的语法可能是一个很好的补充,但我可以没有它。
The thing I dislike about C++ const logic is that it is about the reference and not about the object that is referenced. If I have a "const T *" there is no guarantee that someone holding a non-const pointer will not modify the state of the object. As such, it does not help in any way to avoid race conditions in multi-threaded systems nor does it help in implementing persistent containers.
In my opinion it is very helpful to have a concept of immutable classes and lack of immutable containers in a standard library is a mistake in any language. Since these should exhibit observable immutability but will likely need to be able to change internal/invisible state for efficiency reasons I think const-syntax would be of little help.
Scala has the immutable classes we need to either use directly or base other immutable classes on. That is extremely valuable. Additional syntax might be a nice addition but I can live without it.
因为 C++ const 在复杂系统中并不是那么好。
不,你不能,因为实现(可能在某个看不见的库中)可以消除常量。如果没有 const,其他语言必须以更安全的方式强制执行不变性(例如,请参阅 @Margus 的答案中的 Collections.unmodifyingList() )。
Const 只是编译器读取的文档。文档通常很有帮助,但有时会产生误导。
对我来说,聚合是 const 经常失败的地方。例如,我经常想声明一个方法不会更改向量,但可能会更改它的成员(或返回非常量成员引用)。我必须将其全部设为常量或全部非常量,或者为每种组合发明新的类型变体。
“可变”弥补了一些聚合问题,但引入了更多的复杂性和误用。
Because C++ const is not that great in complex systems.
No, you can't, because the implementation (which may be in a library somewhere out of sight) can cast the constness away. Without const, other languages have to enforce the immutability in safer ways (see Collections.unmodifiableList() in @Margus's answer, for instance).
Const is just documentation that the compiler reads. Documentation is usually helpful but sometimes misleading.
Aggregation is where const often breaks down for me. I often want to declare, for instance, that a method will not change the vector but may change a member of it (or return a non-const member reference). I have to make it all const or all nonconst or invent new type variations for every combination.
'mutable' makes up for some of the aggregation issues but introduces more complexity and misuse.
在我看来,Scala 只是提供了更大的灵活性,不会将引用的不变性与其背后结构的[可能的]可变性混合在一起,使您能够根据正在处理的问题做出设计决策。
IMO, Scala just gives more flexibility not mixing up immutability of the reference with [possible] mutability of the structure behind it, giving you ability to make a design decision WRT the problem you're dealing with.
所有 Scala 代码都转换为 Java 代码,这就是我用 Java 制作示例的原因。
这是如何在 Java 中执行此操作:
那么您问发生了什么? CONST 距离实际数组只有 1 步,它可以隐藏实际数组和 Collection 元素,如果使用简单数组,这是不可能的。如果您仍然想修改常量集合,则需要复制它并进行修改。
来源:链接
来源: Java 等效项 - const 从 C++ 的角度来看。
因此 Scala 的等效项是:
这应该翻译为:
这可以解释我对 IttayD 评论的回应,为什么 java 6 与 c++ 编译器不同:
资料来源:链接
说起来很愚蠢,但 Java 常量命名约定是使用大写字母表示变量。其他阅读您代码的人会立即知道标识符是一个固定的常量值,无法更改。
来源:链接
如果您想同时使用集合的可变版本和不可变版本,一个有用的约定是仅导入包 collection.mutable。
来源: Scala Collection API
不确定你的意思转换,但你可能可以这样做:
All Scala code is translated to Java code, that is why I made examples in Java.
This is how to do this in Java:
So what is happening you ask? CONST is 1 step away from actual array, and it enables to hide actual array and the Collection elements, where as using a simple array, this would not be possible. If you would still want to modify constant collection you would need to make a copy of it and modify that.
Source: link
Source: Java equivalents - const from c++ perspective.
So equivalent for Scala is:
This should translate to:
This might explain my response to IttayD comment, why java 6 differs from c++ compiler:
Source: link
Silly to even mention, but Java Constant Naming Conventions is to use uppercase for the variable. Others reading your code will immediately know that the identifier is a fixed, constant value that cannot be changed.
Source: link
A useful convention if you want to use both mutable and immutable versions of collections is to import just the package collection.mutable.
Source: Scala Collection API
Not sure what you mean by converting, but you can probably do: