Каковы самые большие различия между 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 <- ...) *

* Избегайте конечных запятых *