2. Special unapply
class A {
def _1: Int = 1
def _2: String = "text"
}
class B {
def isEmpty = false
def get = new A
}
object K {
def unapply(s: String): B =
new B
}
"text" match {
case K(i, s) =>
println(i, s)
}
3. Case classes more
Теперь понятнее, что же на самом деле
дает case class:
case class Person(name: String)
val ivan = Person("ivan")
ivan.name
ivan match {
case Person(name) =>
}
4. Multiline strings
Многострочные литералы:
val s =
"""
|Some text.
|<- This is margin.
|It will be stripped below.
""".stripMargin
5. Interpolated strings
Можно использовать разные
интерполяторы. Дефолтные - это s и f:
val name = "Alexander"
val city = "Saint-Petersburg"
s"My name is $name. I live in $city."
val height = 1.8311d
f"$name%s’s height is $height%2.2f"
6. Regular expressions
val Decimal = """(-)?(d+)(.d*)?""".r
"1.0" match {
case Decimal(sign, i, d) =>
case _ =>
}
val Decimal(sign, i, d) = "1.0"
val iterator = Decimal findAllIn "1.0 and 2.0, 33"
for (Decimal(sign, i, d) <- iterator) {
println(i)
}
8. Other patterns
object ** {
def unapply(t: (Int, Int)): Some[(Int, Int)] = Some(t)
}
val x, y: Int = 1
(x, y) match {
case (1, 2) | (2, 1) =>
case 1 ** 1 =>
}
9. Pattern guards
Можно накладывать условия на case clause:
val x, y: Int = 1
(x, y) match {
case (a, b) if a == b =>
case _ =>
}
10. Scopes
Scopes - это место в коде, где может быть
объявлена переменная.
● { - начинает новый scope, кроме классов
● Каждый генератор в for statement начинает
новый scope
● Функция начинает новый scope для
параметров
● Case clause начинает новый scope
Переменная объявленная внутри одного scope
не видна снаружи.
11. Names shadowing
Во внутреннем scope можно скрывать имя
определенное во внешнем scope при условии,
что приоритет этого имени не ниже чем у имени
объявленного снаружи.
Это ошибка объявить переменные с одним
именем внутри одного и того же scope.
Существует два вида имен: expressions, types.
13. Implicit conversions
Преследует две главные цели:
● Extension methods
● DSL languages
Позволяет неявно в коде конвертировать
один тип в другой.
14. Implicit conversions
Простейшие примеры:
class RichString(s: String) {
def double: String = s + s
}
implicit def s2r(s: String): RichString = new RichString(s)
"text".double
val r: RichString = "text"
"""^[^d].*""".r
15. Implicit classes
В Scala 2.10 есть более простой вариант:
implicit class RichString(s: String) {
def double: String = s + s
}
"text".double
16. Value classes
Performance overhead на удаление в GC
новых объектов существенный. Поэтому для
extension methods можно сделать так:
implicit class RichString(val s: String)
extends AnyVal {
def double: String = s + s
}
"text".double
17. Implicits search
1. Сначала ищем в scope
2. Если не нашли, то расширяем scope с
помощью companion objects частей типа,
для которого ищем конверсию
18. How to debug implicits?
Неявно это хорошо, когда все работает.
Что делать, если не работает:
● -Xprint:typer параметр для компилятора
● IntelliJ IDEA view implicits tools
19. Magnet pattern
Пример использования implicits:
● Нет проблемы с type erasure для
перегруженных методов
● Автоматически выносится общая часть
для перегруженных методов
● Использование функциональных типов с
перегрузкой
20. Homework
Написать интерпретируемый язык программирования. Синтаксис и
все остальное дело вашего вкуса. Базовая спецификация
следующая:
1. Динамически типизируемый. У целых и вещественных чисел нет
переполнения.
2. Можно объявлять целые, вещественные и стоковые литералы.
3. Можно объявлять переменные и функции. В функциях можно
задавать значения по умолчанию.
4. Можно эти переменные и функции вызывать.
5. Можно создавать структуры без наследования. Просто данные,
и возможно какие-то методы.