Каковы самые большие различия между Scala 2.8 и Scala 2.7?
Я написал довольно большую программу в Scala 2.7.5, и теперь я с нетерпением жду версии 2.8. Но мне интересно, как этот большой скачок в эволюции Scala повлияет на меня.
Каковы будут самые большие различия между этими двумя версиями Scala? И, возможно, самое главное:
- Мне нужно переписать что-нибудь?
- Нужно ли переписывать что-либо только для того, чтобы воспользоваться некоторыми новыми замечательными функциями?
- Что конкретно представляют собой новые функции Scala 2.8 вообще?
Ответы
Ответ 1
Здесь вы можете найти предварительный просмотр новой функции в Scala2.8 (апрель 2009 г.), завершенный недавним в этой статье (июнь 2009 г.)
- Именованные аргументы и аргументы по умолчанию
- Вложенные аннотации
- Объекты пакета
- @specialized
- Улучшенные коллекции (здесь может потребоваться некоторое переписывание)
- REPL получит завершение команды (более в этом и других трюках в этой статье)
- Новые контрольные абстракции (продолжение или разрыв)
- Улучшения (оболочка Swing, производительность,...)
"Код перезаписи" не является обязательством (за исключением использования некоторых улучшенных коллекций), но некоторые функции, такие как продолжение (Wikipedia: абстрактное представление состояния управления или "остальная часть вычисления" или "остальная часть кода для быть выполненным" ) может дать вам несколько новых идей. Хорошее введение найдено здесь, написанное Daniel (у которого также есть опубликовал много более подробный и конкретный ответ в этом потоке).
Примечание: Scala в Netbeans, похоже, работает с некоторыми 2.8 ночными сборками (по сравнению с официальная страница для 2.7.x)
Ответ 2
Выполнение прыжка
При переносе компилятор может предоставить вам некоторые защитные сети.
- Скомпилируйте старый код против 2.7.7
с
-deprecation
, и следуйте
рекомендации от всех возражений
предупреждения.
-
Обновите свой код для использования
незаполненные пакеты. Это можно сделать
механически путем многократного запуска
это поиск регулярных выражений
заменить.
s/^(package com.example.project.*)\.(\w+)/$1\npackage $2/g
-
Скомпилируйте с компилятором 2.8.0, используя параметры командной строки paranoid -deprecation -Xmigration -Xcheckinit -Xstrict-warnings -Xwarninit
-
Если вы получаете ошибки с ошибкой could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]
, вам нужно добавить неявный параметр (или, эквивалентно, связанный с контекстом) параметр типа.
До:
scala> def listToArray[T](ls: List[T]): Array[T] = ls.toArray
<console>:5: error: could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]
def listToArray[T](ls: List[T]): Array[T] = ls.toArray ^
После:
scala> def listToArray[T: Manifest](ls: List[T]): Array[T] = ls.toArray
listToArray: [T](ls: List[T])(implicit evidence$1: Manifest[T])Array[T]
scala> def listToArray[T](ls: List[T])(implicit m: Manifest[T]): Array[T] = ls.toArray
listToArray: [T](ls: List[T])(implicit m: Manifest[T])Array[T]
Любой метод, который вызывает listToArray
, и сам принимает T
как параметр типа, также должен принять манифест как неявный параметр. Подробнее см. Массивы SID.
-
Слишком долго вы столкнетесь с такой ошибкой:
scala> collection.Map(1 -> 2): Map[Int, Int]
<console>:6: error: type mismatch;
found : scala.collection.Map[Int,Int]
required: Map[Int,Int]
collection.Map(1 -> 2): Map[Int, Int]
^
Вам нужно понять, что тип Map
является псевдонимом в Predef для collection.immutable.Map
.
object Predef {
type Map[A, B] = collection.immutable.Map[A, B]
val Map = collection.immutable.Map
}
Существует три типа с именем Map
- интерфейс только для чтения: collection.Map
, неизменяемая реализация: collection.immutable.Map
и изменяемая реализация: collection.mutable.Map
. Кроме того, библиотека определяет поведение в параллельном наборе признаков MapLike
, но это действительно деталь реализации.
Использование преимуществ
- Заменить некоторую перегрузку метода с помощью именованных параметров и параметров по умолчанию.
-
Используйте сгенерированный метод классов copy
.
scala> case class Foo(a: Int, b: String)
defined class Foo
scala> Foo(1, "a").copy(b = "b")
res1: Foo = Foo(1,b)
- Обобщите сигнатуры методов от
List
до Seq
или Iterable
или Traversable
. Поскольку классы сбора находятся в чистой иерархии, вы можете принять более общий тип.
- Интеграция с библиотеками Java с помощью аннотаций. Теперь вы можете указать вложенные аннотации и мелкозернистый контроль относительно того, нацелены ли аннотации на поля или методы. Это помогает использовать Spring или JPA с кодом Scala.
Есть много других новых функций, которые можно безопасно игнорировать при запуске миграции, например @specialized
и Continuations.
Ответ 3
Ответ VonC трудно улучшить, поэтому я даже не попытаюсь. Я расскажу о других вещах, которые он не упомянул.
Во-первых, некоторые устаревшие вещи пойдут. Если в вашем коде есть предупреждения об утомлении, скорее всего, он больше не будет компилироваться.
Далее расширяется библиотека Scala. В основном, обычные маленькие шаблоны, такие как перехват исключений в Either
или Option
, или преобразование AnyRef в Option с null
, отображаемое в None
. Эти вещи могут в основном проходить незамеченными, но я устаю размещать что-то в блоге, а потом уже рассказываю об этом уже на Scala 2.8. Ну, на самом деле, я не устаю от этого, но, скорее, и счастливо, привык к этому. И я не говорю здесь о Коллекциях, которые получают серьезную ревизию.
Теперь было бы неплохо, если бы люди разместили фактические примеры таких улучшений библиотек, как ответы. Я бы с радостью поддержал все такие ответы.
REPL не получает только завершение команды. Он получает много материала, в том числе возможность исследовать AST для объекта или возможность вставлять точки останова в код, который попадает в REPL.
Кроме того, компилятор Scala модифицируется, чтобы обеспечить быструю частичную компиляцию для IDE, что означает, что мы можем ожидать, что они станут намного более "knowledgable" о Scala - путем запроса самого компилятора Scala о коде.
Одно большое изменение, скорее всего, останется незамеченным многими, хотя оно уменьшит проблемы как для библиотек, так и для пользователей. Прямо сейчас, если вы пишете следующее:
package com.mystuff.java.wrappers
import java.net._
Вы импортируете библиотеку не Java net
, а com.mystuff.java
net
library, а com
, com.mystuff
, com.mystuff.java
и com.mystuff.java.wrappers
все попали в область видимости, и java
можно найти внутри com.mystuff
. При Scala 2.8 только wrappers
получает область действия. Поскольку иногда вы хотите, чтобы часть остального была в Scope, теперь доступен альтернативный синтаксис package
:
package com.mystuff.factories
package ligthbulbs
что эквивалентно:
package com.mystuff.factories {
package lightbulbs {
...
}
}
И получается, что в область видимости отображаются как factories
, так и lightbulbs
.
Ответ 4
Нужно ли переписывать что-нибудь?
def takesArray(arr: Array[AnyRef]) {…}
def usesVarArgs(obs: AnyRef*) {
takesArray(obs)
}
должно стать
def usesVarArgs(obs: AnyRef*) {
takesArray(obs.toArray)
}
Мне пришлось посетить IRC-канал для этого, но потом понял, что я должен был начать здесь.
Ответ 5
Вот контрольный список от Эрика Уиллигерса, который использовал Scala с 2.2. Некоторые из этих материалов, похоже, датируются более поздними пользователями.
* Явно импортировать из внешних пакетов *
Предположим, что
package a
class B
Изменить
package a.c
class D extends B
к
package a.c
import a.B
class D extends B
или
package a
package c
class D extends B
* При импорте из внешнего пакета используйте полное имя пакета
Предположим, что
package a.b
object O { val x = 1 }
Изменить
package a.b.c
import b.O.x
к
package a.b.c
import a.b.O.x
* При явном указании параметров типа в вызовах метода контейнера добавьте новые параметры типа *
Изменить
list.map[Int](f)
к
list.map[Int, List[Int]](f)
Изменить
map.transform[Value](g)
к
map.transform[Value, Map[Key, Value]](g)
* Создайте отсортированную карту, используя Заказ вместо преобразования в Упорядоченный *
[scalac] found : (String) => Ordered[String]
[scalac] required: Ordering[String]
[scalac] TreeMap[String, Any](map.toList: _*)(stringToCaseInsensitiveOrdered _)
* Импортируйте неявные преобразования, которые заменяют scala.collection.jcl *
* Неизменяемая карта .update будет обновлена *
*** Мигрировать из новых устаревших методов List -
* elements
* remove
* sort
* List.flatten(someList)
* List.fromString(someList, sep)
* List.make
*** Использовать методы List * diff
* iterator
* filterNot
* sortWith
* someList.flatten
* someList.split(sep)
* List.fill
* classpath при использовании scala.tools.nsc.Settings *
http://thread.gmane.org/gmane.comp.lang.scala/18245/focus=18247 settings.classpath.value = System.getProperty( "java.class.path" )
* Избегайте ошибок: _ должен следовать методу; не может следовать (Any) = > Boolean *
Заменить
list.filter(that.f _)
с
list.filter(that f _)
или
list.filter(that.f(_))
<Р → → * Миграция из устаревших методов перечисления iterator
map
*Использовать методы перечисления values.iterator
values.map
* Миграция из устаревшего Iterator.fromValues(a, b, c, d)
*Используйте Iterator(a, b, c, d)
* Избегать устаревшего типа Collection
*Вместо этого используйте Iterable
* Изменить порядок инициализации *
Предположим, что
trait T {
val v
val w = v + v
}
Заменить
class C extends T {
val v = "v"
}
с
class C extends {
val v = "v"
} with T
* Избегайте ненужных val
в for (val x <- ...)
*
* Избегайте конечных запятых *