Как я могу изменить нулевой список? - PullRequest
6 голосов
/ 18 декабря 2010

Вы знаете ту сцену в До свидания и спасибо всем рыбам , где Артур так безумно счастлив, что останавливает официанта и требует знать: «Почему эта еда такая хорошая?»Я в такой ситуации.Кажется, что Scala делает именно то, что я хочу, но я не понимаю, как это происходит.Рассмотрим следующее:

scala> var v = Nil:List[String];
v: List[String] = List()

scala> v.length
res38: Int = 0

scala> v ::= "Hello"

scala> v.length
res39: Int = 1

scala> Nil.length
res40: Int = 0

На что именно вы надеетесь, но как это происходит?

Nil - это объект, расширяющий List [Nothing], который является подтипомList [String], так что назначение работает нормально, но это список неизменный , не так ли?Так что я не должен быть в состоянии добавить к этому.Но я могу добавить к нему, или, по крайней мере, я могу добавить к v, который, как я думал, указывает на ноль.v изменяется, а Nil - нет.

Итак, WTF?Есть ли у Scala какая-то умная семантика копирования-на-изменении, о которой я не знаю?Действительно ли Nil - это функция, которая возвращает пустые списки?В более широком смысле, есть ли способ, которым я мог бы заставить REPL ответить на эти вопросы?

Ответы [ 4 ]

16 голосов
/ 18 декабря 2010

Когда Scala видит

v ::= "Hello"

, он сначала проверяет, знает ли v метод ::=.В этом случае (тип List) это не так, поэтому , потому что метод состоит только из символов и заканчивается знаком = , он пытается что-то другое:

v = v.::("Hello")

который, кстати, записан "Hello" :: v в инфиксной записи.Теперь, поскольку v знает метод ::, он работает и возвращает новый List, который затем присваивается v, как указано.

Кстати, он предшествует, а не добавляется.

4 голосов
/ 18 декабря 2010

Когда вы используете ключевое слово var, вы не «переводите на final» в смысле Java.Вместо этого var допускает переназначение.Когда вы звоните оператору ::=, вы фактически переназначаете то, на что указывает v.Оператор ::= возвращает новый список, а не исходный список с добавленным к нему «Hello».Следовательно, v теперь указывает на «Hello», а не на список Nil.

Здесь, посмотрите это:

var myThing = new List(1, 2, 3)
var myOhterThing = myThing

myThing = new List(1, 2, 3, 4)

Это почти то же самое, что сказать «возьми первыйсписок, скопируйте его и добавьте к нему «4». Теперь назначьте «myThing», чтобы указать на этот список. "Используя этот оператор, вы фактически сделали то же самое.Если написать это так, вы увидите это.

3 голосов
/ 18 декабря 2010

Попробуйте это с val v, чтобы увидеть, что можно изменить.:)

2 голосов
/ 18 декабря 2010

Ноль неизменен. Когда вы обращаетесь к нему (: :), вы получаете новый экземпляр, который также неизменен.

Попробуйте это:

val v1 = Nil
val v2 = "Hello" :: v1
v1 == v2 

(вы получите false, поскольку они не указывают на один и тот же объект)

Учитывая, что v - это переменная, вы можете переназначить ей значения.

Итак, когда у вас есть:

v ::= "Hello" // what you really have is:
v = "Hello" :: v  // or
v = "Hello" :: Nil // or
v = List("Hello")

Приведенное выше создает новый список, а Nil остается без изменений. Это похоже на добавление String в Java. Поскольку String является неизменным, вы никогда не меняете один экземпляр, а только создаете новые.

Поскольку ноль не изменился, длина ноль = 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...