我是Scala世界的新手,现在我正在阅读名为“Scala in Action”的书(由Nilanjan Raychaudhuri编写),即第97页的“可变对象需要不变”的部分,我不明白以下部分直接取自上述书籍。
假设ListBuffer是协变的,以下代码片段在没有任何编译问题的情况下工作:
scala> val mxs: ListBuffer[String] = ListBuffer("pants")
mxs: scala.collection.mutable.ListBuffer[String] =
ListBuffer(pants)
scala> val everything: ListBuffer[Any] = mxs
scala> everything += 1
res4: everything.type = ListBuffer(1, pants)
你能发现问题吗?因为一切都是Any类型,你可以存储一个 将整数值转换为字符串集合。这是一场等待发生的灾难。为了避免这些问题,它始终是一个问题 使可变对象不变的好主意。
我会有以下问题......
1)实际上有哪种everything
? String
或Any
?声明是“val everything: ListBuffer[Any]
”,因此我希望Any
因为所有内容都应该是Any
的类型,所以我认为Integer
和{{{{}}}没有任何问题1}}在一个String
中。如何将整数值存储到字符串集合中如何写?为何灾难???我为什么要使用List(不可变)而不是ListBuffer(可变)?我没看见有分别。我找到了很多答案,可变集合应该具有类型不变量,并且不可变集合应该具有协变类型,但为什么呢?
2)最后一部分“ListBuffer[Any]
”是什么意思? “everything.type”是什么意思?我想res4: everything.type = ListBuffer(1, pants)
没有任何名为everything
的方法/函数或变量。为什么没有ListBuffer [Any]或ListBuffer [String]?
非常感谢,
安德鲁
答案 0 :(得分:5)
1 这看起来不像是一个问题,所以我必须进一步细分:
everything
为ListBuffer[_]
,已删除参数类型。根据JVM,它对某些对象保持32位或64位引用。类型ListBuffer[String]
和ListBuffer[Any]
是编译器在编译时知道的类型。如果它"知道"两件相互矛盾的事情,那显然非常糟糕。 "我没有看到任何问题让Integer和String in
一个ListBuffer [Any]" 。在Int
中String
和ListBuffer[Any]
没有问题,因为ListBuffer
是不变的。但是,在您的假设示例中,ListBuffer
是协变的,因此您要在Int
中存储ListBuffer[String]
。如果有人稍后从Int
获得ListBuffer[String]
,并尝试将其解释为String
,那么它显然非常糟糕。
"如何将整数值存储到集合中 字符串如何写?" 为什么你要做一些显然非常糟糕的事情,如上所述?
"为什么灾难???" 它不会是一场重大灾难。 Java一直与协变阵列一起生活。它不会导致灾难,它只是坏事和烦人。
"我为什么要使用List(这是不可变的)而不是ListBuffer(这是可变的)?" 没有绝对的命令可以告诉你永远使用List
并永远不要使用ListBuffer
。在适当的时候使用两者。在99.999%的情况下,List
当然更合适,因为您使用List
来表示数据的方式比设计需要ListBuffer
的本地可变状态的复杂算法更频繁。
"我找到了许多可变收集的答案 应该具有类型不变量和不可变集合应该 有协变类型,但为什么?" 。这是错误的,你过度简化了。例如,内涵不可变集既不应该是协变的,也不应该是不变的,而是逆变。在适当的时候,你应该使用协方差,逆变和不变性。 Drive Tables,也许你觉得它很有用。
2 这是This little silly illustration has proven unreasonably effective for explaining the difference,就像下面的例子一样:
scala> val x = "hello"
x: String = hello
scala> val y: x.type = x
y: x.type = hello
答案 1 :(得分:0)
我同意@Andrey所说的大部分内容我只想补充一点,协方差和逆变只属于不可变结构,书中提出的练习只是一个例子,所以人们可以理解但是不可能实现一个可变的具有协变性的结构,您无法使其编译。
作为练习,您可以尝试实现<div class="modal fade" id="edit" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Editer mon Profile</h4>
</div>
<div class="modal-body">
<div class="span4 offset2 cards">
{{ form_start(form, { 'action': path('fos_user_profile_edit'), 'attr': { 'class': 'fos_user_profile_edit' } }) }}
{{ form_widget(form) }}
<div>
<input class="btn btn-success" type="submit" value="{{ 'profile.edit.submit'|trans }}" />
</div>
{{ form_end(form) }}
</div>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
,但是如果不欺骗编译器将<script src="{{ asset('js/bootstrap.js') }}"></script>
<script src="{{ asset('js/modal.jss') }}"></script>
<link href="{{ asset('css/bootstrap.css') }}" rel="stylesheet">
放在任何地方