Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introducción a Scala

Introducción a Scala

Pequeña introducción a Scala presentada en ValenciaJUG meetup en Septiembre de 2015

Miguel Olivares

October 30, 2016
Tweet

More Decks by Miguel Olivares

Other Decks in Programming

Transcript

  1. Agenda Introducción Primeros pasos Clases y objetos Case classes y

    pattern matching Higher order functions / Collections Trending projects 4 / 54
  2. Scala Scalable language Martin Odersky en la EPFL ~2003 Tipado

    estático Programación funcional + orientación a objetos 6 / 54
  3. Lenguaje de la JVM Genera bytecode Rendimiento similar a Java

    Buena interoperabilidad con Java 8 / 54
  4. Conciso Alto nivel: // java boolean nameHasUpperCase = false; for

    (int i = 0; i < name.length(); ++i) { if (Character.isUpperCase(name.charAt(i))) { nameHasUpperCase = true; break; } } // scala val nameHasUpperCase = name.exists(_.isUpperCase) Inferencia de tipos 9 / 54
  5. Tipado estático Evita errores en tiempo de compilación Es más

    fácil refactorizar Documentación 10 / 54
  6. Definiendo variables val s1 = "Hola Mundo" // Inmutable! var

    s2 = "Hola Mundo" // s2 puede ser reasignado posteriormente El tipo de s1 y s2 ha sido inferido! 12 / 54
  7. Definiendo variables val s1 = "Hola Mundo" // Inmutable! var

    s2 = "Hola Mundo" // s2 puede ser reasignado posteriormente El tipo de s1 y s2 ha sido inferido! Aunque a veces hay que tener cuidado: val l1 = 1 // Queria un Long pero ha inferido un Int val l2 = 1L // Long! 13 / 54
  8. Definiendo variables val s1 = "Hola Mundo" // Inmutable! var

    s2 = "Hola Mundo" // s2 puede ser reasignado posteriormente El tipo de s1 y s2 ha sido inferido! Aunque a veces hay que tener cuidado: val l1 = 1 // Queria un Long pero ha inferido un Int val l2 = 1L // Long! Siempre se puede explicitar el tipo: val l1: Long = 1 14 / 54
  9. Definiendo funciones Las funciones son objetos Se declaran con la

    palabra reservada def No tiene return def f(param1: Int, param2: String): Int = { 1 } 15 / 54
  10. Definiendo funciones En scala las funciones son objetos Se declaran

    con la palabra reservada def No tiene return def f(param1: Int, param2: String): Int = { 1 } El tipo de retorno puede ser inferido def f(param1: Int, param2: String) = { 1 } 16 / 54
  11. Definiendo funciones En scala las funciones son objetos Se declaran

    con la palabra reservada def No tiene return def f(param1: Int, param2: String): Int = { 1 } El tipo de retorno puede ser inferido def f(param1: Int, param2: String) = { 1 } Las llaves no son necesarias si el cuerpo de la función es una única expresión def f(param1: Int, param2: String) = 1 17 / 54
  12. Estructuras de control: if if es una expresión así que

    devuelve un valor que puede ser asignado a una variable val i = 2 val v = if (i % 2 == 0) "par" else "impar" 18 / 54
  13. Estructuras de control: if if es una expresión así que

    devuelve un valor que puede ser asignado a una variable val i = 2 val v = if (i % 2 == 0) "par" else "impar" v será de tipo String, si el bloque if devuelve un tipo distinto al bloque else, el tipo inferido será el primer tipo padre común val i = 2 val v = if (i % 2 == 0) "par" else 1 // v es de tipo Any 19 / 54
  14. Estructuras de control: for for también es una expresión así

    que devuelve un valor val list1 = List(1, 2, 3) val list2 = List(2, 3, 4) val list3 = for { x <- list1 y <- list2 } yield (x * y) 20 / 54
  15. Overview // Java class SomeClass { private int i; private

    String s; public MyClass(int i, String s) { this.i = i; this.s = s; } } // scala class SomeClass(i: Int, s: String) 22 / 54
  16. Getters y setters En scala no se suelen definir getters

    y setters Puedes indicar con val y var en la definición de clase si tus atributos tienen o no getters y setters // con el identificador val, los atributos pueden ser leidos desde fuera class Person(val name: String) val p1 = new Person("John Doe") p1.name // "John Doe" p1.name = "Otro nombre" // Error! 23 / 54
  17. Getters y setters En scala no se suelen definir getters

    y setters Puedes indicar con val y var en la definición de clase si tus atributos tienen o no getters y setters // con el identificador val, los atributos pueden ser leidos desde fuera class Person(val name: String) val p1 = new Person("John Doe") p1.name // "John Doe" p1.name = "Otro nombre" // Error! // con el identificador var los atributos pueden ser leidos y escritos desde fuera class Person(var name: String) val p1 = new Person("John Doe") p1.name // "John Doe" p1.name = "Otro nombre" p1.name // "Otro Nombre" 24 / 54
  18. Definiendo atributos y métodos class A(a: Int) { private val

    b = 1 protected val c = 2 val d = 7 def method1(): Int = { ??? } } Se puede definir otros constructores class B(a: Int, b: Int) { def this(a: Int) = this(a, 0) } 25 / 54
  19. Operadores No hay restrición de nombres a la hora de

    declarar métodos Además, aquellos métodos que reciben un solo parámetro se pueden usar como operador o notación infija. class A(a: Int) { def +(that: A) = new A(this.a + this.a) } val a1 = new A(1) val a2 = new A(2) val a3 = a1 + a2 // a1.+(a2) 26 / 54
  20. Operadores No hay restrición de nombres a la hora de

    declarar métodos Además, aquellos métodos que reciben un solo parámetro se pueden usar como operador o notación infija. class A(a: Int) { def +(that: A) = new A(this.a + this.a) } val a1 = new A(1) val a2 = new A(2) val a3 = a1 + a2 // a1.+(a2) En scala Int es un objeto, así que: 1 + 2 == 1.+(2) // true!! 27 / 54
  21. objects Si en vez de class utilizamos object estamos declarando

    un "singleton" package mypackage object Matematicas { def sum(a: Int, b: Int): Int = a + b } Muchas veces es solo un "namespace". sum puede ser accedido con mypackage.Matematicas.sum 28 / 54
  22. Companion object Es un objeto que se crea con el

    mismo nombre que la clase Su uso más tipico es el de "factory" El companion object es donde definiríamos los métodos "static" class Person(name: String) object Person { def apply(name: String) = new Person(name) } 29 / 54
  23. Companion object Es un objeto que se crea con el

    mismo nombre que la clase Su uso más tipico es el de "factory" El companion object es donde definiríamos los métodos "static" class Person(name: String) object Person { def apply(name: String) = new Person(name) } Person es tambien un singleton ahora, así que podemos crear objetos Person sin el uso de new val p1 = Person("John Doe") val p2 = Person.apply("John Doe") 30 / 54
  24. traits Similar a las interfaces de java Puedes dar implementación

    a los métodos trait Printable { // Tiene que ser implementado def format(): String // Implementación por defecto def print(): Unit = println(this.format) } 31 / 54
  25. traits Similar a las interfaces de java Puedes dar implementación

    a los métodos trait Printable { // Tiene que ser implementado def format(): String // Implementación por defecto def print(): Unit = println(this.format) } Si en una clase dejas un método sin implementar tienes que denotarla como abstract abstract class Exec { def run(): Unit } 32 / 54
  26. Inheritance Como en Java, en Scala solo se puede extender

    de una clase. class A class B extends A 33 / 54
  27. Inheritance Como en Java, en Scala solo se puede extender

    de una clase. class A class B extends A Pero puede tener más de un "mix-in". class A trait Executable trait Printable class B extends A with Executable with Printable 34 / 54
  28. Case classes Se definen con el identificador case Sus parametros

    tienen el identificador val por defecto Por defecto tiene los métodos toString, hashCode y equals implementados Los métodos apply y unapply también implementados. 36 / 54
  29. Case classes case class Person(name: String) // Decrando una nueva

    persona val p1 = Person("John Doe") // Se puede acceder a sus atributos println(p1.name) //John Doe // Automaticamente genera toString println(p1) //Person(John Doe) // tenemos método equals así que comparar es muy sencillo println(p1 == Person("John Doe")) // true 37 / 54
  30. Pattern matching Permite comparar un objeto contra muchas cláusulas y

    ejecutar la primera que se cumpla Cada cláusula puede ser una constante, una variable o el constructor de una clase 38 / 54
  31. Pattern matching Constantes: val year = 2015 year match {

    case 2014 => "2014" case 2015 => "2015" case _ => "Otro" // _ actúa como wildcard } 39 / 54
  32. Pattern matching Constantes: val year = 2015 year match {

    case 2014 => "2014" case 2015 => "2015" case _ => "Otro" // _ actúa como wildcard } Variables: year match { case 2014 => "2014" case 2015 => "2015" case y => s"Otro: $y" } 40 / 54
  33. Pattern matching Constantes: val year = 2015 year match {

    case 2014 => "2014" case 2015 => "2015" case _ => "Otro" // _ actúa como wildcard } Variables: year match { case 2014 => "2014" case 2015 => "2015" case y => s"Otro: $y" } Incluso se puede poner condiciones: year match { case y if (y == 2014 || y == 2015) => y.toString case y => s"Otro: $y" } 41 / 54
  34. Pattern Matching Case classes: case class Person(name: String, age: Int)

    val p1 = Person("John Doe", 43) p1 match { case Person("John Doe", 40) => "Match en todos los valores del constructor" case Person("Juan Nadie", a) => "Match por nombre, mientras que la edad es asignada a u case Person(n, a) => s"Persona cuyo nombre es $n y edad $a" case p @ Person(n, a) => p.toString } 42 / 54
  35. Higher order functions Son funciones que o bien reciben una

    función como parámetro o devuelven una función. En scala las funciones son "ciudadanos de primer order". 44 / 54
  36. Higher order functions Son funciones que o bien reciben una

    función como parámetro o devuelven una función. En scala las funciones son "ciudadanos de primer order". Es decir, podemos especificar que nuestra expresión devuelve una función o asignar una función a una variable. val f1: Int => Int = (x: Int) => x + 1 val f2: Int => Int = x => x + 1 val f3: Int => Int = _ + 1 45 / 54
  37. Higher order functions Es muy intuitivo ver estas funciones applicadas

    a colecciones: map val l = List(1, 2, 3) l.map(_ + 1) // List(2, 3, 4) 46 / 54
  38. Higher order functions Es muy intuitivo ver estas funciones applicadas

    a colecciones: map val l = List(1, 2, 3) l.map(_ + 1) // List(2, 3, 4) filter l.filter(_ % 2 == 1) // List(1, 3) 47 / 54
  39. Higher order functions Es muy intuitivo ver estas funciones applicadas

    a colecciones: map val l = List(1, 2, 3) l.map(_ + 1) // List(2, 3, 4) filter l.filter(_ % 2 == 1) // List(1, 3) exists l.exists(_ % 2 == 1) // true 48 / 54
  40. Higher order functions Es muy intuitivo ver estas funciones applicadas

    a colecciones: map val l = List(1, 2, 3) l.map(_ + 1) // List(2, 3, 4) filter l.filter(_ % 2 == 1) // List(1, 3) exists l.exists(_ % 2 == 1) // true flatMap def friends(id: Int): Set[Int] = ??? def friendsOfFriends(id: Int): Set[Int] = friends(id) flatMap friends 49 / 54
  41. Play Framework Web framework Escrito en Scala pero con soporte

    nativo para Java API HTTP asíncrona No sigue las convenciones JEE 51 / 54
  42. Akka Framework para desarrollar aplicaciones concurrentes y distribuidas Escrito en

    Scala pero con soporte nativo para Java Modelo de actores Reactive Manifesto (Resilience, Elastic, Responsive, Message Driven) 52 / 54