Scala

Личный сайт Go-разработчика из Казани

Scala - the scalable language

1///////////////////////////////////////////////// 2// 0. Basics 3///////////////////////////////////////////////// 4/* 5 Setup Scala: 6 7 1) Download Scala - http://www.scala-lang.org/downloads 8 2) Unzip/untar to your favorite location and put the bin subdir in your `PATH` environment variable 9*/ 10 11/* 12 Try the REPL 13 14 Scala has a tool called the REPL (Read-Eval-Print Loop) that is analogous to 15 commandline interpreters in many other languages. You may type any Scala 16 expression, and the result will be evaluated and printed. 17 18 The REPL is a very handy tool to test and verify code. Use it as you read 19 this tutorial to quickly explore concepts on your own. 20*/ 21 22// Start a Scala REPL by running `scala`. You should see the prompt: 23$ scala 24scala> 25 26// By default each expression you type is saved as a new numbered value 27scala> 2 + 2 28res0: Int = 4 29 30// Default values can be reused. Note the value type displayed in the result.. 31scala> res0 + 2 32res1: Int = 6 33 34// Scala is a strongly typed language. You can use the REPL to check the type 35// without evaluating an expression. 36scala> :type (true, 2.0) 37(Boolean, Double) 38 39// REPL sessions can be saved 40scala> :save /sites/repl-test.scala 41 42// Files can be loaded into the REPL 43scala> :load /sites/repl-test.scala 44Loading /sites/repl-test.scala... 45res2: Int = 4 46res3: Int = 6 47 48// You can search your recent history 49scala> :h? 501 2 + 2 512 res0 + 2 523 :save /sites/repl-test.scala 534 :load /sites/repl-test.scala 545 :h? 55 56// Now that you know how to play, let's learn a little scala... 57 58///////////////////////////////////////////////// 59// 1. Basics 60///////////////////////////////////////////////// 61 62// Single-line comments start with two forward slashes 63 64/* 65 Multi-line comments, as you can already see from above, look like this. 66*/ 67 68// Printing, and forcing a new line on the next print 69println("Hello world!") 70println(10) 71// Hello world! 72// 10 73 74// Printing, without forcing a new line on next print 75print("Hello world") 76print(10) 77// Hello world10 78 79// Declaring values is done using either var or val. 80// val declarations are immutable, whereas vars are mutable. Immutability is 81// a good thing. 82val x = 10 // x is now 10 83x = 20 // error: reassignment to val 84var y = 10 85y = 20 // y is now 20 86 87/* 88 Scala is a statically typed language, yet note that in the above declarations, 89 we did not specify a type. This is due to a language feature called type 90 inference. In most cases, Scala compiler can guess what the type of a variable 91 is, so you don't have to type it every time. We can explicitly declare the 92 type of a variable like so: 93*/ 94val z: Int = 10 95val a: Double = 1.0 96 97// Notice automatic conversion from Int to Double, result is 10.0, not 10 98val b: Double = 10 99 100// Boolean values 101true 102false 103 104// Boolean operations 105!true // false 106!false // true 107true == false // false 10810 > 5 // true 109 110// Math is as per usual 1111 + 1 // 2 1122 - 1 // 1 1135 * 3 // 15 1146 / 2 // 3 1156 / 4 // 1 1166.0 / 4 // 1.5 1176 / 4.0 // 1.5 118 119 120// Evaluating an expression in the REPL gives you the type and value of the result 121 1221 + 7 123 124/* The above line results in: 125 126 scala> 1 + 7 127 res29: Int = 8 128 129 This means the result of evaluating 1 + 7 is an object of type Int with a 130 value of 8 131 132 Note that "res29" is a sequentially generated variable name to store the 133 results of the expressions you typed, your output may differ. 134*/ 135 136"Scala strings are surrounded by double quotes" 137'a' // A Scala Char 138// 'Single quote strings don't exist' <= This causes an error 139 140// Strings have the usual Java methods defined on them 141"hello world".length 142"hello world".substring(2, 6) 143"hello world".replace("C", "3") 144 145// They also have some extra Scala methods. See also: scala.collection.immutable.StringOps 146"hello world".take(5) 147"hello world".drop(5) 148 149// String interpolation: notice the prefix "s" 150val n = 45 151s"We have $n apples" // => "We have 45 apples" 152 153// Expressions inside interpolated strings are also possible 154val a = Array(11, 9, 6) 155s"My second daughter is ${a(0) - a(2)} years old." // => "My second daughter is 5 years old." 156s"We have double the amount of ${n / 2.0} in apples." // => "We have double the amount of 22.5 in apples." 157s"Power of 2: ${math.pow(2, 2)}" // => "Power of 2: 4" 158 159// Formatting with interpolated strings with the prefix "f" 160f"Power of 5: ${math.pow(5, 2)}%1.0f" // "Power of 5: 25" 161f"Square root of 122: ${math.sqrt(122)}%1.4f" // "Square root of 122: 11.0454" 162 163// Raw strings, ignoring special characters. 164raw"New line feed: \n. Carriage return: \r." // => "New line feed: \n. Carriage return: \r." 165 166// Some characters need to be "escaped", e.g. a double quote inside a string: 167"They stood outside the \"Rose and Crown\"" // => "They stood outside the "Rose and Crown"" 168 169// Triple double-quotes let strings span multiple rows and contain quotes 170val html = """<form id="daform"> 171 <p>Press belo', Joe</p> 172 <input type="submit"> 173 </form>""" 174 175 176///////////////////////////////////////////////// 177// 2. Functions 178///////////////////////////////////////////////// 179 180// Functions are defined like so: 181// 182// def functionName(args...): ReturnType = { body... } 183// 184// If you come from more traditional languages, notice the omission of the 185// return keyword. In Scala, the last expression in the function block is the 186// return value. 187def sumOfSquares(x: Int, y: Int): Int = { 188 val x2 = x * x 189 val y2 = y * y 190 x2 + y2 191} 192 193// The { } can be omitted if the function body is a single expression: 194def sumOfSquaresShort(x: Int, y: Int): Int = x * x + y * y 195 196// Syntax for calling functions is familiar: 197sumOfSquares(3, 4) // => 25 198 199// You can use parameters names to specify them in different order 200def subtract(x: Int, y: Int): Int = x - y 201 202subtract(10, 3) // => 7 203subtract(y=10, x=3) // => -7 204 205// In most cases (with recursive functions the most notable exception), function 206// return type can be omitted, and the same type inference we saw with variables 207// will work with function return values: 208def sq(x: Int) = x * x // Compiler can guess return type is Int 209 210// Functions can have default parameters: 211def addWithDefault(x: Int, y: Int = 5) = x + y 212addWithDefault(1, 2) // => 3 213addWithDefault(1) // => 6 214 215 216// Anonymous functions look like this: 217(x: Int) => x * x 218 219// Unlike defs, even the input type of anonymous functions can be omitted if the 220// context makes it clear. Notice the type "Int => Int" which means a function 221// that takes Int and returns Int. 222val sq: Int => Int = x => x * x 223 224// Anonymous functions can be called as usual: 225sq(10) // => 100 226 227// If each argument in your anonymous function is 228// used only once, Scala gives you an even shorter way to define them. These 229// anonymous functions turn out to be extremely common, as will be obvious in 230// the data structure section. 231val addOne: Int => Int = _ + 1 232val weirdSum: (Int, Int) => Int = (_ * 2 + _ * 3) 233 234addOne(5) // => 6 235weirdSum(2, 4) // => 16 236 237 238// The return keyword exists in Scala, but it only returns from the inner-most 239// def that surrounds it. 240// WARNING: Using return in Scala is error-prone and should be avoided. 241// It has no effect on anonymous functions. For example here you may expect foo(7) should return 17 but it returns 7: 242def foo(x: Int): Int = { 243 val anonFunc: Int => Int = { z => 244 if (z > 5) 245 return z // This line makes z the return value of foo! 246 else 247 z + 2 // This line is the return value of anonFunc 248 } 249 anonFunc(x) + 10 // This line is the return value of foo 250} 251 252foo(7) // => 7 253 254///////////////////////////////////////////////// 255// 3. Flow Control 256///////////////////////////////////////////////// 257 2581 to 5 259val r = 1 to 5 260r.foreach(println) 261 262r foreach println 263// NB: Scala is quite lenient when it comes to dots and brackets - study the 264// rules separately. This helps write DSLs and APIs that read like English 265 266// Why doesn't `println` need any parameters here? 267// Stay tuned for first-class functions in the Functional Programming section below! 268(5 to 1 by -1) foreach (println) 269 270// A while loop 271var i = 0 272while (i < 10) { println("i " + i); i += 1 } 273 274while (i < 10) { println("i " + i); i += 1 } // Yes, again. What happened? Why? 275 276i // Show the value of i. Note that while is a loop in the classical sense - 277 // it executes sequentially while changing the loop variable. while is very 278 // fast, but using the combinators and comprehensions above is easier 279 // to understand and parallelize 280 281// A do-while loop 282i = 0 283do { 284 println("i is still less than 10") 285 i += 1 286} while (i < 10) 287 288// Recursion is the idiomatic way of repeating an action in Scala (as in most 289// other functional languages). 290// Recursive functions need an explicit return type, the compiler can't infer it. 291// Here it's Unit, which is analogous to a `void` return type in Java 292def showNumbersInRange(a: Int, b: Int): Unit = { 293 print(a) 294 if (a < b) 295 showNumbersInRange(a + 1, b) 296} 297showNumbersInRange(1, 14) 298 299 300// Conditionals 301 302val x = 10 303 304if (x == 1) println("yeah") 305if (x == 10) println("yeah") 306if (x == 11) println("yeah") 307if (x == 11) println("yeah") else println("nay") 308 309println(if (x == 10) "yeah" else "nope") 310val text = if (x == 10) "yeah" else "nope" 311 312 313///////////////////////////////////////////////// 314// 4. Data Structures 315///////////////////////////////////////////////// 316 317val a = Array(1, 2, 3, 5, 8, 13) 318a(0) // Int = 1 319a(3) // Int = 5 320a(21) // Throws an exception 321 322val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo") 323m("fork") // java.lang.String = tenedor 324m("spoon") // java.lang.String = cuchara 325m("bottle") // Throws an exception 326 327val safeM = m.withDefaultValue("no lo se") 328safeM("bottle") // java.lang.String = no lo se 329 330val s = Set(1, 3, 7) 331s(0) // Boolean = false 332s(1) // Boolean = true 333 334/* Look up the documentation of map here - 335 * https://www.scala-lang.org/api/current/scala/collection/immutable/Map.html 336 * and make sure you can read it 337 */ 338 339 340// Tuples 341 342(1, 2) 343 344(4, 3, 2) 345 346(1, 2, "three") 347 348(a, 2, "three") 349 350// Why have this? 351val divideInts = (x: Int, y: Int) => (x / y, x % y) 352 353// The function divideInts gives you the result and the remainder 354divideInts(10, 3) // (Int, Int) = (3,1) 355 356// To access the elements of a tuple, use _._n where n is the 1-based index of 357// the element 358val d = divideInts(10, 3) // (Int, Int) = (3,1) 359 360d._1 // Int = 3 361d._2 // Int = 1 362 363// Alternatively you can do multiple-variable assignment to tuple, which is more 364// convenient and readable in many cases 365val (div, mod) = divideInts(10, 3) 366 367div // Int = 3 368mod // Int = 1 369 370 371///////////////////////////////////////////////// 372// 5. Object Oriented Programming 373///////////////////////////////////////////////// 374 375/* 376 Aside: Everything we've done so far in this tutorial has been simple 377 expressions (values, functions, etc). These expressions are fine to type into 378 the command-line interpreter for quick tests, but they cannot exist by 379 themselves in a Scala file. For example, you cannot have just "val x = 5" in 380 a Scala file. Instead, the only top-level constructs allowed in Scala are: 381 382 - objects 383 - classes 384 - case classes 385 - traits 386 387 And now we will explain what these are. 388*/ 389 390// classes are similar to classes in other languages. Constructor arguments are 391// declared after the class name, and initialization is done in the class body. 392class Dog(br: String) { 393 // Constructor code here 394 var breed: String = br 395 396 // Define a method called bark, returning a String 397 def bark = "Woof, woof!" 398 399 // Values and methods are assumed public. "protected" and "private" keywords 400 // are also available. 401 private def sleep(hours: Int) = 402 println(s"I'm sleeping for $hours hours") 403 404 // Abstract methods are simply methods with no body. If we uncomment the 405 // def line below, class Dog would need to be declared abstract like so: 406 // abstract class Dog(...) { ... } 407 // def chaseAfter(what: String): String 408} 409 410val mydog = new Dog("greyhound") 411println(mydog.breed) // => "greyhound" 412println(mydog.bark) // => "Woof, woof!" 413 414 415// The "object" keyword creates a type AND a singleton instance of it. It is 416// common for Scala classes to have a "companion object", where the per-instance 417// behavior is captured in the classes themselves, but behavior related to all 418// instance of that class go in objects. The difference is similar to class 419// methods vs static methods in other languages. Note that objects and classes 420// can have the same name. 421object Dog { 422 def allKnownBreeds = List("pitbull", "shepherd", "retriever") 423 def createDog(breed: String) = new Dog(breed) 424} 425 426 427// Case classes are classes that have extra functionality built in. A common 428// question for Scala beginners is when to use classes and when to use case 429// classes. The line is quite fuzzy, but in general, classes tend to focus on 430// encapsulation, polymorphism, and behavior. The values in these classes tend 431// to be private, and only methods are exposed. The primary purpose of case 432// classes is to hold immutable data. They often have few methods, and the 433// methods rarely have side-effects. 434case class Person(name: String, phoneNumber: String) 435 436// Create a new instance. Note cases classes don't need "new" 437val george = Person("George", "1234") 438val kate = Person("Kate", "4567") 439 440// With case classes, you get a few perks for free, like getters: 441george.phoneNumber // => "1234" 442 443// Per field equality (no need to override .equals) 444Person("George", "1234") == Person("Kate", "1236") // => false 445 446// Easy way to copy 447// otherGeorge == Person("George", "9876") 448val otherGeorge = george.copy(phoneNumber = "9876") 449 450// And many others. Case classes also get pattern matching for free, see below. 451 452// Traits 453// Similar to Java interfaces, traits define an object type and method 454// signatures. Scala allows partial implementation of those methods. 455// Constructor parameters are not allowed. Traits can inherit from other 456// traits or classes without parameters. 457 458trait Dog { 459 def breed: String 460 def color: String 461 def bark: Boolean = true 462 def bite: Boolean 463} 464class SaintBernard extends Dog { 465 val breed = "Saint Bernard" 466 val color = "brown" 467 def bite = false 468} 469 470scala> val b = new SaintBernard 471res0: SaintBernard = SaintBernard@3e57cd70 472scala> b.breed 473res1: String = Saint Bernard 474scala> b.bark 475res2: Boolean = true 476scala> b.bite 477res3: Boolean = false 478 479// A trait can also be used as Mixin. The class "extends" the first trait, 480// but the keyword "with" can add additional traits. 481 482trait Bark { 483 def bark: String = "Woof" 484} 485trait Dog { 486 def breed: String 487 def color: String 488} 489class SaintBernard extends Dog with Bark { 490 val breed = "Saint Bernard" 491 val color = "brown" 492} 493 494scala> val b = new SaintBernard 495b: SaintBernard = SaintBernard@7b69c6ba 496scala> b.bark 497res0: String = Woof 498 499 500///////////////////////////////////////////////// 501// 6. Pattern Matching 502///////////////////////////////////////////////// 503 504// Pattern matching is a powerful and commonly used feature in Scala. Here's how 505// you pattern match a case class. NB: Unlike other languages, Scala cases do 506// not need breaks, fall-through does not happen. 507 508def matchPerson(person: Person): String = person match { 509 // Then you specify the patterns: 510 case Person("George", number) => "We found George! His number is " + number 511 case Person("Kate", number) => "We found Kate! Her number is " + number 512 case Person(name, number) => "We matched someone : " + name + ", phone : " + number 513} 514 515// Regular expressions are also built in. 516// Create a regex with the `r` method on a string: 517val email = "(.*)@(.*)".r 518 519// Pattern matching might look familiar to the switch statements in the C family 520// of languages, but this is much more powerful. In Scala, you can match much 521// more: 522def matchEverything(obj: Any): String = obj match { 523 // You can match values: 524 case "Hello world" => "Got the string Hello world" 525 526 // You can match by type: 527 case x: Double => "Got a Double: " + x 528 529 // You can specify conditions: 530 case x: Int if x > 10000 => "Got a pretty big number!" 531 532 // You can match case classes as before: 533 case Person(name, number) => s"Got contact info for $name!" 534 535 // You can match regular expressions: 536 case email(name, domain) => s"Got email address $name@$domain" 537 538 // You can match tuples: 539 case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c" 540 541 // You can match data structures: 542 case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c" 543 544 // You can nest patterns: 545 case List(List((1, 2, "YAY"))) => "Got a list of list of tuple" 546 547 // Match any case (default) if all previous haven't matched 548 case _ => "Got unknown object" 549} 550 551// In fact, you can pattern match any object with an "unapply" method. This 552// feature is so powerful that Scala lets you define whole functions as 553// patterns: 554val patternFunc: Person => String = { 555 case Person("George", number) => s"George's number: $number" 556 case Person(name, number) => s"Random person's number: $number" 557} 558 559 560///////////////////////////////////////////////// 561// 7. Functional Programming 562///////////////////////////////////////////////// 563 564// Scala allows methods and functions to return, or take as parameters, other 565// functions or methods. 566 567val add10: Int => Int = _ + 10 // A function taking an Int and returning an Int 568List(1, 2, 3) map add10 // List(11, 12, 13) - add10 is applied to each element 569 570// Anonymous functions can be used instead of named functions: 571List(1, 2, 3) map (x => x + 10) 572 573// And the underscore symbol, can be used if there is just one argument to the 574// anonymous function. It gets bound as the variable 575List(1, 2, 3) map (_ + 10) 576 577// If the anonymous block AND the function you are applying both take one 578// argument, you can even omit the underscore 579List("Dom", "Bob", "Natalia") foreach println 580 581 582// Combinators 583// Using `s` from above: 584// val s = Set(1, 3, 7) 585 586s.map(sq) 587 588val sSquared = s.map(sq) 589 590sSquared.filter(_ < 10) 591 592sSquared.reduce (_+_) 593 594// The filter function takes a predicate (a function from A -> Boolean) and 595// selects all elements which satisfy the predicate 596List(1, 2, 3) filter (_ > 2) // List(3) 597case class Person(name: String, age: Int) 598List( 599 Person(name = "Dom", age = 23), 600 Person(name = "Bob", age = 30) 601).filter(_.age > 25) // List(Person("Bob", 30)) 602 603 604// Certain collections (such as List) in Scala have a `foreach` method, 605// which takes as an argument a type returning Unit - that is, a void method 606val aListOfNumbers = List(1, 2, 3, 4, 10, 20, 100) 607aListOfNumbers foreach (x => println(x)) 608aListOfNumbers foreach println 609 610// For comprehensions 611 612for { n <- s } yield sq(n) 613 614val nSquared2 = for { n <- s } yield sq(n) 615 616for { n <- nSquared2 if n < 10 } yield n 617 618for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared 619 620/* NB Those were not for loops. The semantics of a for loop is 'repeat', whereas 621 a for-comprehension defines a relationship between two sets of data. */ 622 623 624///////////////////////////////////////////////// 625// 8. Implicits 626///////////////////////////////////////////////// 627 628/* WARNING WARNING: Implicits are a set of powerful features of Scala, and 629 * therefore it is easy to abuse them. Beginners to Scala should resist the 630 * temptation to use them until they understand not only how they work, but also 631 * best practices around them. We only include this section in the tutorial 632 * because they are so commonplace in Scala libraries that it is impossible to 633 * do anything meaningful without using a library that has implicits. This is 634 * meant for you to understand and work with implicits, not declare your own. 635 */ 636 637// Any value (vals, functions, objects, etc) can be declared to be implicit by 638// using the, you guessed it, "implicit" keyword. Note we are using the Dog 639// class from section 5 in these examples. 640implicit val myImplicitInt = 100 641implicit def myImplicitFunction(breed: String) = new Dog("Golden " + breed) 642 643// By itself, implicit keyword doesn't change the behavior of the value, so 644// above values can be used as usual. 645myImplicitInt + 2 // => 102 646myImplicitFunction("Pitbull").breed // => "Golden Pitbull" 647 648// The difference is that these values are now eligible to be used when another 649// piece of code "needs" an implicit value. One such situation is implicit 650// function arguments: 651def sendGreetings(toWhom: String)(implicit howMany: Int) = 652 s"Hello $toWhom, $howMany blessings to you and yours!" 653 654// If we supply a value for "howMany", the function behaves as usual 655sendGreetings("John")(1000) // => "Hello John, 1000 blessings to you and yours!" 656 657// But if we omit the implicit parameter, an implicit value of the same type is 658// used, in this case, "myImplicitInt": 659sendGreetings("Jane") // => "Hello Jane, 100 blessings to you and yours!" 660 661// Implicit function parameters enable us to simulate type classes in other 662// functional languages. It is so often used that it gets its own shorthand. The 663// following two lines mean the same thing: 664// def foo[T](implicit c: C[T]) = ... 665// def foo[T : C] = ... 666 667 668// Another situation in which the compiler looks for an implicit is if you have 669// obj.method(...) 670// but "obj" doesn't have "method" as a method. In this case, if there is an 671// implicit conversion of type A => B, where A is the type of obj, and B has a 672// method called "method", that conversion is applied. So having 673// myImplicitFunction above in scope, we can say: 674"Retriever".breed // => "Golden Retriever" 675"Sheperd".bark // => "Woof, woof!" 676 677// Here the String is first converted to Dog using our function above, and then 678// the appropriate method is called. This is an extremely powerful feature, but 679// again, it is not to be used lightly. In fact, when you defined the implicit 680// function above, your compiler should have given you a warning, that you 681// shouldn't do this unless you really know what you're doing. 682 683 684///////////////////////////////////////////////// 685// 9. Misc 686///////////////////////////////////////////////// 687 688// Importing things 689import scala.collection.immutable.List 690 691// Import all "sub packages" 692import scala.collection.immutable._ 693 694// Import multiple classes in one statement 695import scala.collection.immutable.{List, Map} 696 697// Rename an import using '=>' 698import scala.collection.immutable.{List => ImmutableList} 699 700// Import all classes, except some. The following excludes Map and Set: 701import scala.collection.immutable.{Map => _, Set => _, _} 702 703// Java classes can also be imported. Scala syntax can be used 704import java.swing.{JFrame, JWindow} 705 706// Your program's entry point is defined in a scala file using an object, with a 707// single method, main: 708object Application { 709 def main(args: Array[String]): Unit = { 710 // stuff goes here. 711 } 712} 713 714// Files can contain multiple classes and objects. Compile with scalac 715 716 717 718 719// Input and output 720 721// To read a file line by line 722import scala.io.Source 723for(line <- Source.fromFile("myfile.txt").getLines()) 724 println(line) 725 726// To write a file use Java's PrintWriter 727val writer = new PrintWriter("myfile.txt") 728writer.write("Writing line for line" + util.Properties.lineSeparator) 729writer.write("Another line here" + util.Properties.lineSeparator) 730writer.close()

Further resources