Merge pull request #857 from geoffliu/master

[Scala/en] Reorganize the Scala tutorial
This commit is contained in:
Adam Bard 2014-11-12 19:52:39 +02:00
commit 493cff577c

View File

@ -4,6 +4,7 @@ filename: learnscala.scala
contributors:
- ["George Petrov", "http://github.com/petrovg"]
- ["Dominic Bou-Samra", "http://dbousamra.github.com"]
- ["Geoff Liu", "http://geoffliu.me"]
filename: learn.scala
---
@ -20,34 +21,47 @@ Scala - the scalable language
scala>
This is the so called REPL. You can run commands in the REPL. Let's do just
that:
This is the so called REPL (Read-Eval-Print Loop). You may type any valid
Scala expression into it, and the result will be printed. We will explain what
Scala files look like further into this tutorial, but for now, let's start
with some basics.
*/
println(10) // prints the integer 10
println("Boo!") // printlns the string Boo!
/////////////////////////////////////////////////
// 1. Basics
/////////////////////////////////////////////////
// Single line comments start with two forward slashes
// Some basics
/*
Multi line comments, as you can already see from above, look like this.
*/
// Printing, and forcing a new line on the next print
println("Hello world!")
println(10)
// Printing, without forcing a new line on next print
print("Hello world")
// Declaring values is done using either var or val
// Declaring values is done using either var or val.
// val declarations are immutable, whereas var's are mutable. Immutability is
// a good thing.
val x = 10 // x is now 10
x = 20 // error: reassignment to val
var x = 10
x = 20 // x is now 20
var y = 10
y = 20 // y is now 20
// Single line comments start with two forward slashes
/*
Multi line comments look like this.
Scala is a statically typed language, yet note that in the above declarations, we did not specify
a type. This is due to a language feature called type inference. In most cases, Scala compiler can
guess what the type of a variable is, so you don't have to type it every time. We can explicitly
declare the type of a variable like so:
*/
val z: Int = 10
val a: Double = 1.0
val b: Double = 10 // Notice automatic conversion from Int to Double, result is 10.0, not 10
// Boolean values
true
@ -64,9 +78,11 @@ true == false // false
2 - 1 // 1
5 * 3 // 15
6 / 2 // 3
6 / 4 // 1
6.0 / 4 // 1.5
// Evaluating a command in the REPL gives you the type and value of the result
// Evaluating an expression in the REPL gives you the type and value of the result
1 + 7
@ -78,13 +94,53 @@ true == false // false
This means the result of evaluating 1 + 7 is an object of type Int with a
value of 8
1+7 will give you the same result
Note that "res29" is a sequentially generated variable name to store the results of the
expressions you typed, your output may differ.
*/
"Scala strings are surrounded by double quotes"
'a' // A Scala Char
// 'Single quote strings don't exist' <= This causes an error
// Everything is an object, including a function. Type these in the REPL:
// Strings have the usual Java methods defined on them
"hello world".length
"hello world".substring(2, 6)
"hello world".replace("C", "3")
7 // results in res30: Int = 7 (res30 is just a generated var name for the result)
// They also have some extra Scala methods. See also: scala.collection.immutable.StringOps
"hello world".take(5)
"hello world".drop(5)
// String interpolation: notice the prefix "s"
val n = 45
s"We have $n apples" // => "We have 45 apples"
// Expressions inside interpolated strings are also possible
val a = Array(11, 9, 6)
s"My second daughter is ${a(0) - a(2)} years old." // => "My second daughter is 5 years old."
s"We have double the amount of ${n / 2.0} in apples." // => "We have double the amount of 22.5 in apples."
s"Power of 2: ${math.pow(2, 2)}" // => "Power of 2: 4"
// Formatting with interpolated strings with the prefix "f"
f"Power of 5: ${math.pow(5, 2)}%1.0f" // "Power of 5: 25"
f"Square root of 122: ${math.sqrt(122)}%1.4f" // "Square root of 122: 11.0454"
// Raw strings, ignoring special characters.
raw"New line feed: \n. Carriage return: \r." // => "New line feed: \n. Carriage return: \r."
// Some characters need to be "escaped", e.g. a double quote inside a string:
"They stood outside the \"Rose and Crown\"" // => "They stood outside the "Rose and Crown""
// Triple double-quotes let strings span multiple rows and contain quotes
val html = """<form id="daform">
<p>Press belo', Joe</p>
<input type="submit">
</form>"""
/////////////////////////////////////////////////
// 2. Functions
/////////////////////////////////////////////////
// The next line gives you a function that takes an Int and returns it squared
(x:Int) => x * x
@ -108,25 +164,65 @@ sq(10) // Gives you this: res33: Int = 100.
// taking an Int and returning an Int.
val add10: Int => Int = _ + 10
// Scala allows methods and functions to return, or take as parameters, other
// functions or methods.
List(1, 2, 3) map add10 // List(11, 12, 13) - add10 is applied to each element
/////////////////////////////////////////////////
// 3. Flow Control
/////////////////////////////////////////////////
// Anonymous functions can be used instead of named functions:
List(1, 2, 3) map (x => x + 10)
1 to 5
val r = 1 to 5
r.foreach( println )
// 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)
r foreach println
// NB: Scala is quite lenient when it comes to dots and brackets - study the
// rules separately. This helps write DSLs and APIs that read like English
// 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
(5 to 1 by -1) foreach ( println )
// A while loops
var i = 0
while (i < 10) { println("i " + i); i+=1 }
while (i < 10) { println("i " + i); i+=1 } // Yes, again. What happened? Why?
i // Show the value of i. Note that while is a loop in the classical sense -
// it executes sequentially while changing the loop variable. while is very
// fast, faster that Java // loops, but using the combinators and
// comprehensions above is easier to understand and parallelize
// A do while loop
do {
println("x is still less than 10");
x += 1
} while (x < 10)
// Tail recursion is an idiomatic way of doing recurring things in Scala.
// Recursive functions need an explicit return type, the compiler can't infer it.
// Here it's Unit.
def showNumbersInRange(a:Int, b:Int):Unit = {
print(a)
if (a < b)
showNumbersInRange(a + 1, b)
}
showNumbersInRange(1,14)
// Conditionals
// Data structures
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. Data Structures
/////////////////////////////////////////////////
val a = Array(1, 2, 3, 5, 8, 13)
a(0)
@ -175,110 +271,25 @@ d._1
d._2
/////////////////////////////////////////////////
// 5. Object Oriented Programming
/////////////////////////////////////////////////
// Combinators
/*
Aside: Everything we've done so far in this tutorial has been simple
expressions (values, functions, etc). These expressions are fine to type into
the command-line interpreter for quick tests, but they cannot exist by
themselves in a Scala file. For example, you cannot have just "val x = 5" in
a Scala file. Instead, the only top-level constructs allowed in Scala are:
s.map(sq)
- objects
- classes
- case classes
- traits
val sSquared = s. map(sq)
And now we will explain what these are.
*/
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))
// Scala a foreach method defined on certain collections that takes a type
// returning Unit (a void method)
val aListOfNumbers = Set(1,2,3,45,234)
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. */
// Loops and iteration
1 to 5
val r = 1 to 5
r.foreach( println )
r foreach println
// NB: Scala is quite lenient when it comes to dots and brackets - study the
// rules separately. This helps write DSLs and APIs that read like English
(5 to 1 by -1) foreach ( println )
// A while loops
var i = 0
while (i < 10) { println("i " + i); i+=1 }
while (i < 10) { println("i " + i); i+=1 } // Yes, again. What happened? Why?
i // Show the value of i. Note that while is a loop in the classical sense -
// it executes sequentially while changing the loop variable. while is very
// fast, faster that Java // loops, but using the combinators and
// comprehensions above is easier to understand and parallelize
// A do while loop
do {
println("x is still less than 10");
x += 1
} while (x < 10)
// Tail recursion is an idiomatic way of doing recurring things in Scala.
// Recursive functions need an explicit return type, the compiler can't infer it.
// Here it's Unit.
def showNumbersInRange(a:Int, b:Int):Unit = {
print(a)
if (a < b)
showNumbersInRange(a + 1, b)
}
showNumbersInRange(1,14)
// Conditionals
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"
// Object oriented features
// Classname is Dog
class Dog(br: String) {
var breed: String = br
//A method called bark, returning a String
@ -296,8 +307,6 @@ println(mydog.bark) // => "Woof, woof!"
// Classes can contain nearly any other construct, including other classes,
// functions, methods, objects, case classes, traits etc.
// Case classes
case class Person(name:String, phoneNumber:String)
@ -305,8 +314,12 @@ case class Person(name:String, phoneNumber:String)
Person("George", "1234") == Person("Kate", "1236")
// Objects and traits coming soon!
// Pattern matching
/////////////////////////////////////////////////
// 6. Pattern Matching
/////////////////////////////////////////////////
val me = Person("George", "1234")
@ -345,49 +358,77 @@ matcher("52917") // => "No match on '52917'"
matcher("52752-16432-22178-47917") // => "Serial key: 52752, 16432, 22178, 47917"
// Strings
/////////////////////////////////////////////////
// 7. Functional Programming
/////////////////////////////////////////////////
"Scala strings are surrounded by double quotes" //
'a' // A Scala Char
'Single quote strings don't exist' // Error
"Strings have the usual Java methods defined on them".length
"They also have some extra Scala methods.".reverse
// Scala allows methods and functions to return, or take as parameters, other
// functions or methods.
// Seealso: scala.collection.immutable.StringOps
List(1, 2, 3) map add10 // List(11, 12, 13) - add10 is applied to each element
println("ABCDEF".length)
println("ABCDEF".substring(2, 6))
println("ABCDEF".replace("C", "3"))
// Anonymous functions can be used instead of named functions:
List(1, 2, 3) map (x => x + 10)
// String interpolation
val n = 45
println(s"We have $n apples") // => "We have 45 apples"
// 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)
// Expressions inside interpolated strings are also possible
val a = Array(11, 9, 6)
println(s"My second daughter is ${a(0) - a(2)} years old.") // => "My second daughter is 5 years old."
println(s"We have double the amount of ${n / 2.0} in apples.") // => "We have double the amount of 22.5 in apples."
println(s"Power of 2: ${math.pow(2, 2)}") // => "Power of 2: 4"
// Formatting with interpolated strings (note the prefixed f)
println(f"Power of 5: ${math.pow(5, 2)}%1.0f") // "Power of 5: 25"
println(f"Square root of 122: ${math.sqrt(122)}%1.4f") // "Square root of 122"
// Ignoring special characters.
println(raw"New line feed: \n. Carriage return: \r.") // => "New line feed: \n. Carriage return: \r."
// Some characters need to be 'escaped', e.g. a double quote inside a string:
val a = "They stood outside the \"Rose and Crown\"" // => "They stood outside the "Rose and Crown""
// Triple double-quotes let strings span multiple rows and contain quotes
val html = """<form id="daform">
<p>Press belo', Joe</p>
| <input type="submit">
</form>"""
// 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
// Application structure and organization
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, phoneNumber:String)
List(
Person(name = "Dom", age = 23),
Person(name = "Bob", age = 30)
).filter(_.age > 25) // List(Person("Bob", 30))
// Scala a foreach method defined on certain collections that takes a type
// returning Unit (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
/////////////////////////////////////////////////
Coming soon!
/////////////////////////////////////////////////
// 9. Misc
/////////////////////////////////////////////////
// Importing things
import scala.collection.immutable.List