2019-06-05 14:16:42 +00:00
---
language: Scala
filename: learnscala-es.scala
contributors:
- ["George Petrov", "http://github.com/petrovg"]
- ["Dominic Bou-Samra", "http://dbousamra.github.com"]
- ["Geoff Liu", "http://geoffliu.me"]
- ["Ha-Duong Nguyen", "http://reference-error.org"]
translators:
- ["Pablo Arranz Ropero", "http://arranzropablo.com"]
lang: es-es
---
Scala - El lenguaje escalable
```scala
/////////////////////////////////////////////////
// 0. Básicos
/////////////////////////////////////////////////
/*
Configurar Scala:
1) Descarga Scala - http://www.scala-lang.org/downloads
2) Unzip/untar a tu carpeta elegida y pon la subcarpeta bin en tu variable de entorno `PATH`
*/
/*
Prueba REPL
Scala tiene una herramienta llamada REPL (Read-Eval-Print Loop, en español: Bucle de lectura-evaluación-impresión) que es analogo a interpretes de la linea de comandos en muchos otros lenguajes.
Puedes escribir cualquier expresión en Scala y el resultado será evaluado e impreso.
REPL es una herramienta muy práctica para testear y verificar código.
Puedes usarla mientras lees este tutorial para explorar conceptos por tu cuenta.
*/
// Inicia Scala REPL ejecutando `scala` en tu terminal. Deberías ver:
$ scala
scala>
// Por defecto cada expresión que escribes es guardada como un nuevo valor numerado:
scala> 2 + 2
res0: Int = 4
// Los valores por defecto pueden ser reusados. Fíjate en el tipo del valor mostrado en el resultado...
scala> res0 + 2
res1: Int = 6
// Scala es un lenguaje fuertemente tipado. Puedes usar REPL para comprobar el tipo sin evaluar una expresión.
scala> :type (true, 2.0)
(Boolean, Double)
// Las sesiones REPL pueden ser guardadas
scala> :save /sites/repl-test.scala
// Se pueden cargar archivos en REPL
scala> :load /sites/repl-test.scala
Loading /sites/repl-test.scala...
res2: Int = 4
res3: Int = 6
// Puedes buscar en tu historial reciente
scala> :h?
1 2 + 2
2 res0 + 2
3 :save /sites/repl-test.scala
4 :load /sites/repl-test.scala
5 :h?
// Ahora que sabes como jugar, aprendamos un poco de Scala...
/////////////////////////////////////////////////
// 1. Básicos
/////////////////////////////////////////////////
// Los comentarios de una linea comienzan con dos barras inclinadas
/*
Los comentarios de varias lineas, como ya has visto arriba, se hacen de esta manera.
*/
// Así imprimimos forzando una nueva linea en la siguiente impresión
println("Hola mundo!")
println(10)
// Hola mundo!
// 10
// Así imprimimos sin forzar una nueva linea en la siguiente impresión
print("Hola mundo")
print(10)
// Hola mundo10
// Para declarar valores usamos var o val.
// Valores decalrados con val son inmutables, mientras que los declarados con var son mutables.
// La inmutabilidad es algo bueno.
val x = 10 // x es 10
x = 20 // error: reassignment to val
var y = 10
y = 20 // y es 20
/*
Scala es un lenguaje tipado estáticamente, aunque se puede ver en las expresiones anteriores que no hemos especificado un tipo.
Esto es debido a una funcionalidad del lenguaje llamada inferencia. En la mayoría de los casos, el compilador de Scala puede adivinar cual es el tipo de una variable, así que no hace falta escribirlo siempre.
Podemos declarar explicitamente el tipo de una variable de la siguiente manera:
*/
val z: Int = 10
val a: Double = 1.0
// Observa la conversión automática de Int a Double, el resultado será 10.0, no 10
val b: Double = 10
// Valores Booleanos
true
false
// Operaciones Booleanas
!true // false
!false // true
true == false // false
10 > 5 // true
// Las operaciones matemáticas se realizan como siempre
1 + 1 // 2
2 - 1 // 1
5 * 3 // 15
6 / 2 // 3
6 / 4 // 1
6.0 / 4 // 1.5
6 / 4.0 // 1.5
// Evaluar una expresión en REPL te da el tipo y valor del resultado
1 + 7
/* La linea superior tienen como resultado:
scala> 1 + 7
res29: Int = 8
Esto quiere decir que el resultado de evaluar 1 + 7 es un objeto de tipo Int con valor 8
Observa que "res29" es un nombre de variable secuencialmente generado para almacenar los resultados de las expresiones escritas, la salida que observes puede diferir en este sentido.
*/
"Las cadenas en Scala están rodeadas por comillas dobles"
'a' // Un caracter en Scala
// 'Las cadenas con comillas simples no existen' < = Esto causa un error
// Las cadenas tienen los los típicos metodos de Java definidos
"hello world".length
"hello world".substring(2, 6)
"hello world".replace("C", "3")
// También tienen algunos métodos extra de Scala. Ver: scala.collection.immutable.StringOps
"hello world".take(5)
"hello world".drop(5)
// Interpolación de cadenas: Observa el prefijo "s"
val n = 45
s"Tengo $n manzanas" // => "Tengo 45 manzanas"
// Es posible colocar expresiones dentro de cadenas interpoladas
val a = Array(11, 9, 6)
s"Mi segunda hija tiene ${a(0) - a(2)} años." // => "Mi segunda hija tiene 5 años."
s"Hemos doblado la cantidad de ${n / 2.0} manzanas." // => "Hemos doblado la cantidad de 22.5 manzanas."
s"Potencia de 2: ${math.pow(2, 2)}" // => "Potencia de 2: 4"
// Podemos formatear cadenas interpoladas con el prefijo "f"
f"Potencia de 5: ${math.pow(5, 2)}%1.0f" // "Potencia de 5: 25"
f"Raiz cuadrada de 122: ${math.sqrt(122)}%1.4f" // "Raiz cuadrada de 122: 11.0454"
// Las cadenas puras ignoran caracteres especiales.
raw"Nueva linea: \n. Retorno: \r." // => "Nueva linea: \n. Retorno: \r."
// Algunos caracteres necesitn ser escapados, por ejemplo unas comillas dobles dentro de una cadena:
"Se quedaron fuera de \"Rose and Crown\"" // => "Se quedaron fuera de "Rose and Crown""
// Las triples comillas dobles dejan que las cadenas se expandan por multiples filas y contengan comillas dobles o simples
val html = """< form id = "daform" >
< p > Press belo', Joe< / p >
< input type = "submit" >
< / form > """
/////////////////////////////////////////////////
// 2. Funciones
/////////////////////////////////////////////////
// Las funciones se definen de la siguiente manera:
//
// def nombreFuncion(argumentos...): TipoRetorno = { cuerpo... }
//
// Si estás acostumbrado a lenguajes más tradicionales, observa la omisión de la palabra return.
// En Scala, la última expresión en el bloque de función es el valor de retorno.
def sumaDeCuadrados(x: Int, y: Int): Int = {
val x2 = x * x
val y2 = y * y
x2 + y2
}
// Los { } pueden omitirse si el cuerpo de la función es una única expresión:
def sumaDeCuadradosCorta(x: Int, y: Int): Int = x * x + y * y
// La sintaxis para llamar funciones es familiar:
sumaDeCuadrados(3, 4) // => 25
// Puedes usar los nombres de los parámetros para llamarlos en orden diferente
def restar(x: Int, y: Int): Int = x - y
restar(10, 3) // => 7
restar(y=10, x=3) // => -7
// En la mayoría de los casos (siendo las funciones recursivas la excepción más notable),
// el tipo de retorno de la función puede ser omitido, y la misma inferencia de tipos que vimos con las variables
// funcionará con los valores de retorno de las funciones:
def sq(x: Int) = x * x // El compilador puede adivinar que el tipo de retorno es Int
// Las funciones pueden tener parametros por defecto:
def sumarConDefecto(x: Int, y: Int = 5) = x + y
sumarConDefecto(1, 2) // => 3
sumarConDefecto(1) // => 6
// Las funciones anónimas se escriben así:
(x: Int) => x * x
// Al contrario que los defs, incluso el tipo de entrada de las funciones anónimas puede ser omitido si
// el contexto lo deja claro. Observa el tipo "Int => Int" que significa que es una función
// que recibe Int y retorna Int.
val sq: Int => Int = x => x * x
// Las funciones anónimas pueden ser llamadas como las demás:
sq(10) // => 100
// Si cada argumento en tu función anónima es usado solo una vez,
// Scala te da una manera incluso más corta de definirlos.
// Estas funciones anónimas son extremadamente comunes,
// como será obvio en la sección de estructuras de datos.
val sumarUno: Int => Int = _ + 1
val sumaRara: (Int, Int) => Int = (_ * 2 + _ * 3)
sumarUno(5) // => 6
sumaRara(2, 4) // => 16
// La palabra return existe en Scala, pero solo retorna desde la función más interna que la rodea.
// ADVERTENCIA: Usar return en Scala puede inducir a errores y debe ser evitado
// No tiene efecto en funciones anónimas. Por ejemplo:
def foo(x: Int): Int = {
val funcAnon: Int => Int = { z =>
if (z > 5)
return z // Esta línea hace que z sea el valor de retorno de foo!
else
z + 2 // Esta línea es el valor de retorno de funcAnon
}
anonFunc(x) // Esta línea es el valor de retorno de foo
}
/////////////////////////////////////////////////
// 3. Control del flujo
/////////////////////////////////////////////////
1 to 5
val r = 1 to 5
r.foreach(println)
r foreach println
// Nota: Scala es un lenguaje muy permisivo cuando se trata de puntos y parentesis - estudia las
// reglas separadamente. Esto ayuda a escribir DSLs y APIs que se lean en lenguaje natural.
// Por qué `println` no necesita parámetros aquí?
// Presta atención a las funciones de primera clase en la sección de Programación Funcional más abajo!
(5 to 1 by -1) foreach (println)
// Un bucle while
var i = 0
while (i < 10 ) { println ( " i " + i ) ; i + = 1 }
while (i < 10 ) { println ( " i " + i ) ; i + = 1 } / / Si , de nuevo . Qué ocurrió ? Por qué ?
i // Muestra el valor de i. Observa que while es un loop en el sentido clásico -
// se ejecuta secuencialmente mientras cambia la variable del bucle. while es muy
// rápido, pero los combinadores y comprensiones anteriores son más sencillos
// de entender y paralelizar
// Un bucle do-while
i = 0
do {
println("i es aún menor que 10")
i += 1
} while (i < 10 )
// La recursion es la manera idiomática de repetir una acción en Scala (como en la mayoría de
// lenguajes funcionales).
// Las funciones recursivas necesitan un tipo de retorno explicito, el compilador no puede inferirlo.
// En Scala tenemos Unit, que es análogo al tipo de retorno `void` en Java
def enseñaNumerosEnUnRango(a: Int, b: Int): Unit = {
print(a)
if (a < b )
enseñaNumerosEnUnRango(a + 1, b)
}
enseñaNumerosEnUnRango(1, 14)
// Condicionales
val x = 10
if (x == 1) println("yeah")
if (x == 10) println("yeah")
if (x == 11) println("yeah")
if (x == 11) println("yeah") else println("nay")
println(if (x == 10) "yeah" else "nope")
val text = if (x == 10) "yeah" else "nope"
/////////////////////////////////////////////////
// 4. Estructuras de datos
/////////////////////////////////////////////////
val a = Array(1, 2, 3, 5, 8, 13)
a(0) // Int = 1
a(3) // Int = 5
a(21) // Lanza una excepción
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
m("fork") // java.lang.String = tenedor
m("spoon") // java.lang.String = cuchara
m("bottle") // Lanza una excepción
val mapaSeguro = m.withDefaultValue("no lo se")
mapaSeguro("bottle") // java.lang.String = no lo se
val s = Set(1, 3, 7)
s(0) // Boolean = false
s(1) // Boolean = true
/* Hecha un vistazo a la documentación de Map aquí -
* http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map
* y asegúrate de que puedes leerla
*/
// Tuplas
(1, 2)
(4, 3, 2)
(1, 2, "three")
(a, 2, "three")
// Por qué tener esto?
val dividirEnteros = (x: Int, y: Int) => (x / y, x % y)
// La función dividirEnteros te da el resultado y el resto
dividirEnteros(10, 3) // (Int, Int) = (3,1)
// Para acceder a los elementos de una tupla, usa _._n donde n es el indice (comenzando por 1)
// del elemento
val d = dividirEnteros(10, 3) // (Int, Int) = (3,1)
d._1 // Int = 3
d._2 // Int = 1
// Alternativamente puedes asignar multiples variables desde una tupla, lo que
// resulta más conveniente y legible en muchos casos.
val (div, mod) = dividirEnteros(10, 3)
div // Int = 3
mod // Int = 1
/////////////////////////////////////////////////
// 5. Programación Orientada a Objetos
/////////////////////////////////////////////////
/*
Nota: Todo lo que hemos hecho hasta ahora en este tutorial han sido
simples expresiones (valores, funciones, etc). Estas expresiones son validas
para hacer pruebas rapidas en el interprete de la linea de comandos,
pero no pueden existir por si solas en un archivo de Scala. Por ejemplo,
no puedes tener simplemente "val x = 5" en un archivo Scala. En lugar de eso,
las únicas construcciones de alto nivel en Scala son:
- Objetos
- Clases
- Case clases
- Traits
Y ahora explicaremos lo que son estas.
*/
// Las clases son similares a las clases de otros lenguajes. Los argumentos del constructor
// son declarados despues del nombre de la clase, y la inicialización se hace en el cuerpo de la clase.
class Perro(r: String) {
// Código del constructor aquí
var raza: String = r
// Define un método llamado ladrar, que devuelva un String
def ladrar = "Woof, woof!"
// Los valores y métodos son asumidos como públicos.
// Las palabras "protected" y "private" también son válidas.
private def dormir(horas: Int) =
println(s"Estoy durmiendo $horas horas")
// Los métodos abstractos son simplemente métodos sin cuerpo.
// Si descomentamos la linea de debajo, la clase Perro necesitaría ser abstracta:
// abstract class Perro(...) { ... }
// def perseguir(algo: String): String
}
val miperro = new Dog("greyhound")
println(mydog.raza) // => "greyhound"
println(mydog.ladrar) // => "Woof, woof!"
// La palabra "object" crea un tipo y una instancia singleton de ese tipo.
// Es común que las clases en Scala tengan un "companion object", de manera que
// el comportamiento por instancia es controlado por las clases y el comportamiento
// relacionado a todas las instancias de esa clase es controlado por el objeto
// La relación es similar a los métodos de las clases con los métodos estáticos
// en otros lenguajes. Observa que los objetos y clases pueden tener el mismo nombre.
object Perro {
def todasLasRazasConocidas = List("pitbull", "shepherd", "retriever")
def crearPerro(raza: String) = new Dog(breed)
}
// Case clases son clases que tienen funcionalidad extra añadida. Una pregunta
// común para los principiantes en Scala es cuando usar case clases y cuando usar
// clases. La linea no está bien definida, pero en general, las clases tienden a
// enfocarse en la encapsulación, polimorfismo y comportamiento. Los valores en
// estas clases tienden a ser privados, y solo se exponen los métodos.
// El propósito principal de las case clases es tener datos inmutables.
// A menudo tienen pocos métodos, y los métodos raramente tienen efectos secundarios.
case class Persona(nombre: String, telefono: String)
2019-06-06 14:14:06 +00:00
// Para crear instancia nuevas, observa que las case clases no necesitan "new"
2019-06-05 14:16:42 +00:00
val george = Persona("George", "1234")
val kate = Persona("Kate", "4567")
2019-06-06 14:14:06 +00:00
// Con las case clases tienes unas pocas ventajas, como el acceso a los campos:
george.telefono // => "1234"
2019-06-05 14:16:42 +00:00
2019-06-06 14:14:06 +00:00
// Para la igualdad de campos no necesitas sobreescribir el método equals
Persona("George", "1234") == Persona("Kate", "1236") // => false
2019-06-05 14:16:42 +00:00
2019-06-06 14:14:06 +00:00
// Manera fácil de copiar
// otroGeorge == Persona("George", "9876")
val otroGeorge = george.copy(telefono = "9876")
2019-06-05 14:16:42 +00:00
2019-06-06 14:14:06 +00:00
// Y muchas otras. Las case clases también tienen comparación de patrones, que veremos más abajo.
2019-06-05 14:16:42 +00:00
// Traits
2019-06-06 14:14:06 +00:00
// De manera similar a las interfaces Java, los traits definen un tipo de objeto y métodos.
// Scala permite la implementación parcial de dichos métodos.
// No se permiten parámetros de constructor. Los traits pueden heredar de otros traits o
// clases sin parámetros.
2019-06-05 14:16:42 +00:00
2019-06-06 14:14:06 +00:00
trait Perro {
def raza: String
2019-06-05 14:16:42 +00:00
def color: String
2019-06-06 14:14:06 +00:00
def ladra: Boolean = true
def muerde: Boolean
2019-06-05 14:16:42 +00:00
}
2019-06-06 14:14:06 +00:00
class SanBernardo extends Perro {
val raza = "San Bernardo"
val color = "marrón"
def muerde = false
2019-06-05 14:16:42 +00:00
}
scala> b
2019-06-06 14:14:06 +00:00
res0: SanBernardo = SanBernardo@3e57cd70
scala> b.raza
res1: String = San Bernardo
scala> b.ladra
2019-06-05 14:16:42 +00:00
res2: Boolean = true
2019-06-06 14:14:06 +00:00
scala> b.muerde
2019-06-05 14:16:42 +00:00
res3: Boolean = false
2019-06-06 14:14:06 +00:00
// Un trait tambien puede ser usado mezclado con otros traits.
// La clase extiende el primer trait, pero la palabra "with"
// puede añadir traits adicionales.
2019-06-05 14:16:42 +00:00
2019-06-06 14:14:06 +00:00
trait Ladra {
def ladra: String = "Guau"
2019-06-05 14:16:42 +00:00
}
2019-06-06 14:14:06 +00:00
trait Perro {
def raza: String
2019-06-05 14:16:42 +00:00
def color: String
}
2019-06-06 14:14:06 +00:00
class SanBernardo extends Perro with Ladra {
val raza = "San Bernardo"
val color = "marrón"
2019-06-05 14:16:42 +00:00
}
2019-06-06 14:14:06 +00:00
scala> val b = new SanBernardo
b: SanBernardo = SanBernardo@7b69c6ba
scala> b.ladra
res0: String = Guau
2019-06-05 14:16:42 +00:00
/////////////////////////////////////////////////
2019-06-06 14:14:06 +00:00
// 6. Comparación de patrones
2019-06-05 14:16:42 +00:00
/////////////////////////////////////////////////
2019-06-06 14:14:06 +00:00
// La comparación de patrones es una poderosa función de Scala.
// Ahora veremos como comparar patrones en una case clase.
// Nota: A diferencia de otros lenguajes, Scala "cases" no necesitan
// "break", porque no ejecuta los "case" posteriores.
2019-06-05 14:16:42 +00:00
2019-06-06 14:14:06 +00:00
def comparaPersona(persona: Persona): String = persona match {
// Aqui especificas los patrones:
case Persona("George", telefono) => "Hemos encontrado a George! Su número es " + telefono
case Persona("Kate", telefono) => "Hemos encontrado a Kate! Su número es " + telefono
case Persona(nombre, telefono) => "Hemos encontrado alguien : " + nombre + ", teléfono : " + telefono
2019-06-05 14:16:42 +00:00
}
2019-06-06 14:14:06 +00:00
// Las expresiones regulares también están incorporadas.
// Creas una expresión regular con el método `r` en una cadena:
2019-06-05 14:16:42 +00:00
val email = "(.*)@(.*)".r
2019-06-06 14:14:06 +00:00
// La comparación de patrones puede parecerse al bloque switch en la familia de lenguajes de C,
// pero aquí es mucho más poderosa. En Scala, puedes hacer más comparaciones:
def comparaTodo(obj: Any): String = obj match {
// Puedes comparar valores:
case "Hola mundo" => "Tengo la cadena Hola mundo"
2019-06-05 14:16:42 +00:00
2019-06-06 14:14:06 +00:00
// Puedes comparar tipos:
case x: Double => "Tengo un double: " + x
2019-06-05 14:16:42 +00:00
2019-06-06 14:14:06 +00:00
// Puedes especificar condiciones:
case x: Int if x > 10000 => "Tengo un número muy grande!"
2019-06-05 14:16:42 +00:00
// You can match case classes as before:
case Person(name, number) => s"Got contact info for $name!"
// You can match regular expressions:
case email(name, domain) => s"Got email address $name@$domain"
// You can match tuples:
case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c"
// You can match data structures:
case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c"
// You can nest patterns:
case List(List((1, 2, "YAY"))) => "Got a list of list of tuple"
// Match any case (default) if all previous haven't matched
case _ => "Got unknown object"
}
// In fact, you can pattern match any object with an "unapply" method. This
// feature is so powerful that Scala lets you define whole functions as
// patterns:
val patternFunc: Person => String = {
case Person("George", number) => s"George's number: $number"
case Person(name, number) => s"Random person's number: $number"
}
/////////////////////////////////////////////////
// 7. Functional Programming
/////////////////////////////////////////////////
// Scala allows methods and functions to return, or take as parameters, other
// functions or methods.
val add10: Int => Int = _ + 10 // A function taking an Int and returning an Int
List(1, 2, 3) map add10 // List(11, 12, 13) - add10 is applied to each element
// Anonymous functions can be used instead of named functions:
List(1, 2, 3) map (x => x + 10)
// And the underscore symbol, can be used if there is just one argument to the
// anonymous function. It gets bound as the variable
List(1, 2, 3) map (_ + 10)
// If the anonymous block AND the function you are applying both take one
// argument, you can even omit the underscore
List("Dom", "Bob", "Natalia") foreach println
// Combinators
// Using `s` from above:
// val s = Set(1, 3, 7)
s.map(sq)
val sSquared = s. map(sq)
sSquared.filter(_ < 10 )
sSquared.reduce (_+_)
// The filter function takes a predicate (a function from A -> Boolean) and
// selects all elements which satisfy the predicate
List(1, 2, 3) filter (_ > 2) // List(3)
case class Person(name: String, age: Int)
List(
Person(name = "Dom", age = 23),
Person(name = "Bob", age = 30)
).filter(_.age > 25) // List(Person("Bob", 30))
// Certain collections (such as List) in Scala have a `foreach` method,
// which takes as an argument a type returning Unit - that is, a void method
val aListOfNumbers = List(1, 2, 3, 4, 10, 20, 100)
aListOfNumbers foreach (x => println(x))
aListOfNumbers foreach println
// For comprehensions
for { n < - s } yield sq ( n )
val nSquared2 = for { n < - s } yield sq ( n )
for { n < - nSquared2 if n < 10 } yield n
for { n < - s ; nSquared = n * n if nSquared < 10 } yield nSquared
/* NB Those were not for loops. The semantics of a for loop is 'repeat', whereas
a for-comprehension defines a relationship between two sets of data. */
/////////////////////////////////////////////////
// 8. Implicits
/////////////////////////////////////////////////
/* WARNING WARNING: Implicits are a set of powerful features of Scala, and
* therefore it is easy to abuse them. Beginners to Scala should resist the
* temptation to use them until they understand not only how they work, but also
* best practices around them. We only include this section in the tutorial
* because they are so commonplace in Scala libraries that it is impossible to
* do anything meaningful without using a library that has implicits. This is
* meant for you to understand and work with implicits, not declare your own.
*/
// Any value (vals, functions, objects, etc) can be declared to be implicit by
// using the, you guessed it, "implicit" keyword. Note we are using the Dog
// class from section 5 in these examples.
implicit val myImplicitInt = 100
implicit def myImplicitFunction(breed: String) = new Dog("Golden " + breed)
// By itself, implicit keyword doesn't change the behavior of the value, so
// above values can be used as usual.
myImplicitInt + 2 // => 102
myImplicitFunction("Pitbull").breed // => "Golden Pitbull"
// The difference is that these values are now eligible to be used when another
// piece of code "needs" an implicit value. One such situation is implicit
// function arguments:
def sendGreetings(toWhom: String)(implicit howMany: Int) =
s"Hello $toWhom, $howMany blessings to you and yours!"
// If we supply a value for "howMany", the function behaves as usual
sendGreetings("John")(1000) // => "Hello John, 1000 blessings to you and yours!"
// But if we omit the implicit parameter, an implicit value of the same type is
// used, in this case, "myImplicitInt":
sendGreetings("Jane") // => "Hello Jane, 100 blessings to you and yours!"
// Implicit function parameters enable us to simulate type classes in other
// functional languages. It is so often used that it gets its own shorthand. The
// following two lines mean the same thing:
// def foo[T](implicit c: C[T]) = ...
// def foo[T : C] = ...
// Another situation in which the compiler looks for an implicit is if you have
// obj.method(...)
// but "obj" doesn't have "method" as a method. In this case, if there is an
// implicit conversion of type A => B, where A is the type of obj, and B has a
// method called "method", that conversion is applied. So having
// myImplicitFunction above in scope, we can say:
"Retriever".breed // => "Golden Retriever"
"Sheperd".bark // => "Woof, woof!"
// Here the String is first converted to Dog using our function above, and then
// the appropriate method is called. This is an extremely powerful feature, but
// again, it is not to be used lightly. In fact, when you defined the implicit
// function above, your compiler should have given you a warning, that you
// shouldn't do this unless you really know what you're doing.
/////////////////////////////////////////////////
// 9. Misc
/////////////////////////////////////////////////
// Importing things
import scala.collection.immutable.List
// Import all "sub packages"
import scala.collection.immutable._
// Import multiple classes in one statement
import scala.collection.immutable.{List, Map}
// Rename an import using '=>'
import scala.collection.immutable.{List => ImmutableList}
// Import all classes, except some. The following excludes Map and Set:
import scala.collection.immutable.{Map => _, Set => _ , _}
// Java classes can also be imported. Scala syntax can be used
import java.swing.{JFrame, JWindow}
// Your programs entry point is defined in a scala file using an object, with a
// single method, main:
object Application {
def main(args: Array[String]): Unit = {
// stuff goes here.
}
}
// Files can contain multiple classes and objects. Compile with scalac
// Input and output
// To read a file line by line
import scala.io.Source
for(line < - Source . fromFile ( " myfile . txt " ) . getLines ( ) )
println(line)
// To write a file use Java's PrintWriter
val writer = new PrintWriter("myfile.txt")
writer.write("Writing line for line" + util.Properties.lineSeparator)
writer.write("Another line here" + util.Properties.lineSeparator)
writer.close()
```
## Further resources
* [Scala for the impatient ](http://horstmann.com/scala/ )
* [Twitter Scala school ](http://twitter.github.io/scala_school/ )
* [The scala documentation ](http://docs.scala-lang.org/ )
* [Try Scala in your browser ](http://scalatutorials.com/tour/ )
* Join the [Scala user group ](https://groups.google.com/forum/#!forum/scala-user )