scala lecture #4

Post on 11-Jul-2015

285 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Scala #4Scopes, XML, Scala type system

Scopes

Scopes - это место в коде, где может быть объявлена переменная. ● { - начинает новый scope, кроме классов ● Каждый генератор в for statement

начинает новый scope ● Функция начинает новый scope для

параметров ● Case clause начинает новый scope Переменная объявленная внутри одного scope не видна снаружи.

Names shadowing

Во внутреннем scope можно скрывать имя определенное во внешнем scope при условии, что приоритет этого имени не ниже чем у имени объявленного снаружи.

Это ошибка объявить переменные с одним именем внутри одного и того же scope.

Существует два вида имен: expressions, types.

Think functional

Давайте напишем программу вывода таблицы умножения (см. Programming Scala)

Initialization

Инициализация происходит в обратом порядке, нежели линеаризация. Порядок важно понимать, иначе можно заработать NullPointerException:

Initializationobject InitializationNPE {

class A {

val x1 = "text"

val x2 = x1.length

}

class B extends A {

override val x1 = "text1"

}

def main(args: Array[String]) {

new B

}

}

Initialization

Есть два способа решить эту проблему● Early definitions● Lazy initialization

Early definitions

Если нужно определить что-то до вызова super конструктора, это можно сделать в early definitions:

class B(x: Int)

class A(s: String) extends {

val i = s.toInt

} with B(i * i)

Initialization (early defs)object InitializationNPE {

class A {

val x1 = "text"

val x2 = x1.length

}

class B extends {

override val x1 = "text1"

} with A

def main(args: Array[String]) {

new B

}

}

Lazy values

Scala поддерживает синтиаксис ленивых вычислений. От пользователя требуется лишь объявить переменную, как lazy.

Реализация double-checked locking, что приводит к определенным сложностям.

Initialization (lazy vals)object InitializationNPE {

class A {

lazy val x1 = "text"

val x2 = x1.length

}

class B extends A {

override lazy val x1 = "text1"

}

def main(args: Array[String]) {

new B

}

}

Few words about traits

Как же компилируются traits, рассмотрим простой пример:

trait Base {

def foo() = 1

}

class Child extends Base

Few words about traitspublic interface Base {

int foo();

}

public class Base$class {

public static int foo(Base base) {

return 1;

}

}

public class Child implements Base {

public int foo() {

return Base$class.foo(this);

}

}

Embedded XML

Практически любой валидный XML можно использовать как литерал:

val xml1 = <a>Some text<b/></a>val xml2 = <a>{3 + 4}</a>val xml3 = <a>{"</a>It's just String<a>"}</a>

Если надо написать {, то его можно заэскейпить {{.

XML API

Базовый класс scala.xml.Node.Доступ к subelement через \ “name”.К аттрибутам через \ “@name”.Рекурсивный поиск в глубину \\ “name”.

val xml = <a id="text"><b>S<c></c></b></a>

xml.text // S

xml \ "b" // <b>S<c></c></b>

xml \ "@id" // text

xml \\ "c" // <c></c>

Using XML

Встроенный XML легко использовать для сериализации:

val node = <x></x>

scala.xml.XML.save("File.xml", node)

scala.xml.XML.load("File.xml")

Pattern matching

В pattern matching есть особый синтаксис для XML:

val node = <x></x>

scala.xml.XML.save("File.xml", node)

scala.xml.XML.load("File.xml")

Scala type system

Basic types

● Primitive types● Type designators● Parameterized types● Tuple types● Function types● Infix types● Type projections● Singleton types● Annotated types

Advanced types

● Structural types● Existential types● Method types (internal type)● Polymorphic method types (internal type)● Type constructors (internal type)

Primitive types

Есть несколько важных фич:● Numeric Widening. Если работает weak

conformance, то он автоматический.● Literal Narrowing. Literal с ожидаемым

типом Byte, Short or Char конвертируется.● Value discarding. Если тип Uеnit, то для

любого выражения, есть конверсия.Value classes также наследуются от AnyVal.

Type designators

Это просто любой class, trait или object как тип. Ничего особенного здесь не подразумевается.

Parameterized types

Для type designator и его type parameters есть два правила:● Число type parameters должно of underli

совпадать с числом параметорв соответствующего класса type designator.

● Каждый type parameter должен подходить к type parameter bounds

Tuple types

Синтаксический сахар для TupleN[T1, ..., Tn] типа. Subtyping разрешается также, как и subtyping соответствующего TupleN класс согласно вариантности.Поэтому этот код и не скомпилируется:

object A {

def foo(x: (Int, Int)) = x._1 + x._2

def foo(x: (String, String)) = x._1 + x._2

}

Automatic tupling

Позволяет избежать лишних скобок, особенно это полезно для infix нотации.

object A {

def foo(x: (Int, Int)) = x._1 + x._2

}

A.foo((1, 2))

A.foo(1, 2)

A foo (1, 2)

println(1, 2, 3)

Function type

Уже подробно изученный нами синтаксический сахар. В силу недосмотра в компиляторе это несовсем синтаксический сахар:

val x1: Function1[Int, Int] = x => x + 1

val x2: Int => Int = _ + 1

val y1: Function1[Seq[Int], Int] = x => x.length

val y2: (Int*) => Int = x => x.length

Annotated types

Любой тип можно проаннотировать. С точки зрения системы типов эта аннотация будет проигнорирована:

class A

val a: A @serializable = new A

Infix types

Синтаксический сахар (опять?..)

class :::[T, S]

val x: :::[Int, Int] = new :::

val y: Int ::: Int = new :::

Infix types

Может быть полезно для операторов над типами:

type n[A] = A => Nothing

type ++[T, U] = n[n[T] with n[U]]

type nn[A] = n[n[A]]

type |+|[T, U] = { type λ[X] = nn[X] <:< (T ++ U) }

def size[T : (Int |+| String)#λ] (t: T) = t match {

case i: Int => i

case s: String => s.length

}

top related