From 6178cacd7731a035af8eb9e41cca6b1781040193 Mon Sep 17 00:00:00 2001 From: Ben Luo Date: Thu, 6 Oct 2022 00:55:13 +0800 Subject: [PATCH 1/4] add code tabs in num8 --- .../scala3-book/taste-control-structures.md | 247 +++++++++++++++--- 1 file changed, 209 insertions(+), 38 deletions(-) diff --git a/_overviews/scala3-book/taste-control-structures.md b/_overviews/scala3-book/taste-control-structures.md index 241facb117..bd4ef07cb7 100644 --- a/_overviews/scala3-book/taste-control-structures.md +++ b/_overviews/scala3-book/taste-control-structures.md @@ -19,12 +19,24 @@ Scala has the control structures you find in other programming languages, and al These structures are demonstrated in the following examples. - - ## `if`/`else` -Scala’s `if`/`else` control structure looks similar to other languages: +Scala’s `if`/`else` control structure looks similar to other languages. In Scala 2, it was constructed differently, with parentheses required and curly brackets instead of the keyword `then`: +{% tabs if-else class=tabs-scala-version %} +{% tab 'Scala 2' for=if-else %} +```scala +if (x < 0) { + println("negative") +} else if (x == 0) { + println("zero") +} else { + println("positive") +} +``` +{% endtab %} + +{% tab 'Scala 3' for=if-else %} ```scala if x < 0 then println("negative") @@ -33,51 +45,57 @@ else if x == 0 then else println("positive") ``` +{% endtab %} +{% endtabs %} Note that this really is an _expression_---not a _statement_. This means that it returns a value, so you can assign the result to a variable: +{% tabs if-else-expression class=tabs-scala-version %} +{% tab 'Scala 2' for=if-else-expression %} +```scala +val x = if (a < b) { a } else { b } +``` +{% endtab %} + +{% tab 'Scala 3' for=if-else-expression %} ```scala val x = if a < b then a else b ``` +{% endtab %} +{% endtabs %} As you’ll see throughout this book, _all_ Scala control structures can be used as expressions. > An expression returns a result, while a statement does not. > Statements are typically used for their side-effects, such as using `println` to print to the console. -The `if`/`else` control struture in Scala 2 was constructed differently, with parentheses required and curly brackets instead of the keyword `then`. - -```scala -// Scala 2 syntax -if (test1) { - doX() -} else if (test2) { - doY() -} else { - doZ() -} -``` - ## `for` loops and expressions The `for` keyword is used to create a `for` loop. This example shows how to print every element in a `List`: +{% tabs for-loop class=tabs-scala-version %} +{% tab 'Scala 2' for=for-loop %} ```scala val ints = List(1, 2, 3, 4, 5) -for i <- ints do println(i) +for (i <- ints) println(i) ``` +> The old syntax in Scala 2 `for` structure. -The code `i <- ints` is referred to as a _generator_, and the code that follows the `do` keyword is the _body_ of the loop. - -The old syntax in Scala 2 for this control structure was: +{% endtab %} +{% tab 'Scala 3' for=for-loop %} ```scala -// Scala 2 syntax -for (i <- ints) println(i) +val ints = List(1, 2, 3, 4, 5) + +for i <- ints do println(i) ``` +> The code `i <- ints` is referred to as a _generator_, and the code that follows the `do` keyword is the _body_ of the loop. + +{% endtab %} +{% endtabs %} Again, note the usage of parentheses and the new `for`-`do` in Scala 3. @@ -87,6 +105,15 @@ You can also use one or more `if` expressions inside a `for` loop. These are referred to as _guards_. This example prints all of the numbers in `ints` that are greater than `2`: +{% tabs for-guards class=tabs-scala-version %} +{% tab 'Scala 2' for=for-guards %} +```scala +for ( i <- ints if i > 2) + println(i) +``` +{% endtab %} + +{% tab 'Scala 3' for=for-guards %} ```scala for i <- ints @@ -94,11 +121,23 @@ for do println(i) ``` +{% endtab %} +{% endtabs %} You can use multiple generators and guards. This loop iterates over the numbers `1` to `3`, and for each number it also iterates over the characters `a` to `c`. However, it also has two guards, so the only time the print statement is called is when `i` has the value `2` and `j` is the character `b`: +{% tabs for-guards-multi class=tabs-scala-version %} +{% tab 'Scala 2' for=for-guards-multi %} +```scala +for ( i <- 1 to 3 if i == 2; + j <- 'a' to 'c' if j == 'b' ) + println(s"i = $i, j = $j") // prints: "i = 2, j = b" +``` +{% endtab %} + +{% tab 'Scala 3' for=for-guards-multi %} ```scala for i <- 1 to 3 @@ -108,7 +147,8 @@ for do println(s"i = $i, j = $j") // prints: "i = 2, j = b" ``` - +{% endtab %} +{% endtabs %} ### `for` expressions @@ -117,29 +157,76 @@ The `for` keyword has even more power: When you use the `yield` keyword instead A few examples demonstrate this. Using the same `ints` list as the previous example, this code creates a new list, where the value of each element in the new list is twice the value of the elements in the original list: +{% tabs for-expression_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=for-expression_1 %} +```` +scala> val doubles = for (i <- ints) yield i * 2 +val doubles: List[Int] = List(2, 4, 6, 8, 10) +```` +{% endtab %} + +{% tab 'Scala 3' for=for-expression_1 %} ```` scala> val doubles = for i <- ints yield i * 2 val doubles: List[Int] = List(2, 4, 6, 8, 10) ```` +{% endtab %} +{% endtabs %} Scala’s control structure syntax is flexible, and that `for` expression can be written in several other ways, depending on your preference: +{% tabs for-expressioni_2 class=tabs-scala-version %} +{% tab 'Scala 2' for=for-expressioni_2 %} +```scala +val doubles = for (i <- ints) yield i * 2 +val doubles = for (i <- ints) yield (i * 2) +val doubles = for { i <- ints } yield (i * 2) +``` +{% endtab %} + +{% tab 'Scala 3' for=for-expressioni_2 %} ```scala val doubles = for i <- ints yield i * 2 // style shown above val doubles = for (i <- ints) yield i * 2 val doubles = for (i <- ints) yield (i * 2) val doubles = for { i <- ints } yield (i * 2) ``` +{% endtab %} +{% endtabs %} This example shows how to capitalize the first character in each string in the list: +{% tabs for-expressioni_3 class=tabs-scala-version %} +{% tab 'Scala 2' for=for-expressioni_3 %} +```scala +val names = List("chris", "ed", "maurice") +val capNames = for ( name <- names ) yield name.capitalize +``` +{% endtab %} + +{% tab 'Scala 3' for=for-expressioni_3 %} ```scala val names = List("chris", "ed", "maurice") val capNames = for name <- names yield name.capitalize ``` +{% endtab %} +{% endtabs %} Finally, this `for` expression iterates over a list of strings, and returns the length of each string, but only if that length is greater than `4`: +{% tabs for-expressioni_4 class=tabs-scala-version %} +{% tab 'Scala 2' for=for-expressioni_4 %} +```scala +val fruits = List("apple", "banana", "lime", "orange") + +val fruitLengths = for ( f <- fruits if f.length > 4 ) + yield f.length + +// fruitLengths: List[Int] = List(5, 6, 6) +``` +{% endtab %} + +{% tab 'Scala 3' for=for-expressioni_4 %} ```scala val fruits = List("apple", "banana", "lime", "orange") @@ -153,15 +240,30 @@ yield // fruitLengths: List[Int] = List(5, 6, 6) ``` +{% endtab %} +{% endtabs %} `for` loops and expressions are covered in more detail in the [Control Structures sections][control] of this book, and in the [Reference documentation]({{ site.scala3ref }}/other-new-features/control-syntax.html). - - ## `match` expressions Scala has a `match` expression, which in its most basic use is like a Java `switch` statement: +{% tabs match class=tabs-scala-version %} +{% tab 'Scala 2' for=match %} +```scala +val i = 1 + +// later in the code ... +i match { + case 1 => println("one") + case 2 => println("two") + case _ => println("other") +} +``` +{% endtab %} + +{% tab 'Scala 3' for=match %} ```scala val i = 1 @@ -171,18 +273,53 @@ i match case 2 => println("two") case _ => println("other") ``` +{% endtab %} +{% endtabs %} However, `match` really is an expression, meaning that it returns a result based on the pattern match, which you can bind to a variable: +{% tabs match-expression_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=match-expression_1 %} +```scala +val result = i match { + case 1 => "one" + case 2 => "two" + case _ => "other" +} +``` +{% endtab %} + +{% tab 'Scala 3' for=match-expression_1 %} ```scala val result = i match case 1 => "one" case 2 => "two" case _ => "other" ``` +{% endtab %} +{% endtabs %} `match` isn’t limited to working with just integer values, it can be used with any data type: +{% tabs match-expression_2 class=tabs-scala-version %} +{% tab 'Scala 2' for=match-expression_2 %} +```scala +val p = Person("Fred") + +// later in the code +p match { + case Person(name) if name == "Fred" => + println(s"$name says, Yubba dubba doo") + + case Person(name) if name == "Bam Bam" => + println(s"$name says, Bam bam!") + + case _ => println("Watch the Flintstones!") +} +``` +{% endtab %} + +{% tab 'Scala 3' for=match-expression_2 %} ```scala val p = Person("Fred") @@ -196,9 +333,14 @@ p match case _ => println("Watch the Flintstones!") ``` +{% endtab %} +{% endtabs %} + In fact, a `match` expression can be used to test a variable against many different types of patterns. This example shows (a) how to use a `match` expression as the body of a method, and (b) how to match all the different types shown: +{% tabs match-expression_3 class=tabs-scala-version %} +{% tab 'Scala 3 only' for=match-expression_3 %} ```scala // getClassAsString is a method that takes a single argument of any type. def getClassAsString(x: Matchable): String = x match @@ -213,6 +355,8 @@ getClassAsString(1) // Int getClassAsString("hello") // 'hello' is a String getClassAsString(List(1, 2, 3)) // List ``` +{% endtab %} +{% endtabs %} The method `getClassAsString` takes as a parameter a value of type [Matchable]({{ site.scala3ref }}/other-new-features/matchable.html), which can be any type supporting pattern matching (some types don’t support pattern matching because this could @@ -222,13 +366,26 @@ There’s _much_ more to pattern matching in Scala. Patterns can be nested, results of patterns can be bound, and pattern matching can even be user-defined. See the pattern matching examples in the [Control Structures chapter][control] for more details. - - ## `try`/`catch`/`finally` Scala’s `try`/`catch`/`finally` control structure lets you catch exceptions. It’s similar to Java, but its syntax is consistent with `match` expressions: +{% tabs try class=tabs-scala-version %} +{% tab 'Scala 2' for=try %} +```scala +try { + writeTextToFile(text) +} catch { + case ioe: IOException => println("Got an IOException.") + case nfe: NumberFormatException => println("Got a NumberFormatException.") +} finally { + println("Clean up your resources here.") +} +``` +{% endtab %} + +{% tab 'Scala 3' for=try %} ```scala try writeTextToFile(text) @@ -238,29 +395,45 @@ catch finally println("Clean up your resources here.") ``` - - +{% endtab %} +{% endtabs %} ## `while` loops Scala also has a `while` loop construct. It’s one-line syntax looks like this: +{% tabs while_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=while_1 %} ```scala -while x >= 0 do x = f(x) +while ( x >= 0 ) { x = f(x) } ``` +{% endtab %} -In Scala 2, the syntax was a bit different. The condition was surrounded by parentheses, and -there was no `do` keyword: - +{% tab 'Scala 3' for=while_1 %} ```scala -while (x >= 0) { x = f(x) } +while x >= 0 do x = f(x) ``` +{% endtab %} +{% endtabs %} Scala 3 still supports the Scala 2 syntax for the sake of compatibility. The `while` loop multiline syntax looks like this: +{% tabs while_2 class=tabs-scala-version %} +{% tab 'Scala 2' for=while_2 %} +```scala +var x = 1 + +while (x < 3) { + println(x) + x += 1 +} +``` +{% endtab %} + +{% tab 'Scala 3' for=while_2 %} ```scala var x = 1 @@ -270,14 +443,12 @@ do println(x) x += 1 ``` - - +{% endtab %} +{% endtabs %} ## Custom control structures Thanks to features like by-name parameters, infix notation, fluent interfaces, optional parentheses, extension methods, and higher-order functions, you can also create your own code that works just like a control structure. You’ll learn more about this in the [Control Structures][control] section. - - [control]: {% link _overviews/scala3-book/control-structures.md %} From 4c9c12b544e6efb220398ac675e623e4d93ab9a5 Mon Sep 17 00:00:00 2001 From: Ben Luo Date: Wed, 12 Oct 2022 19:54:29 +0800 Subject: [PATCH 2/4] delete scala2 sentence. --- .../scala3-book/taste-control-structures.md | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/_overviews/scala3-book/taste-control-structures.md b/_overviews/scala3-book/taste-control-structures.md index bd4ef07cb7..d1668fdf4e 100644 --- a/_overviews/scala3-book/taste-control-structures.md +++ b/_overviews/scala3-book/taste-control-structures.md @@ -21,10 +21,11 @@ These structures are demonstrated in the following examples. ## `if`/`else` -Scala’s `if`/`else` control structure looks similar to other languages. In Scala 2, it was constructed differently, with parentheses required and curly brackets instead of the keyword `then`: +Scala’s `if`/`else` control structure looks similar to other languages. {% tabs if-else class=tabs-scala-version %} {% tab 'Scala 2' for=if-else %} + ```scala if (x < 0) { println("negative") @@ -34,9 +35,11 @@ if (x < 0) { println("positive") } ``` + {% endtab %} {% tab 'Scala 3' for=if-else %} + ```scala if x < 0 then println("negative") @@ -45,6 +48,7 @@ else if x == 0 then else println("positive") ``` + {% endtab %} {% endtabs %} @@ -53,15 +57,19 @@ This means that it returns a value, so you can assign the result to a variable: {% tabs if-else-expression class=tabs-scala-version %} {% tab 'Scala 2' for=if-else-expression %} + ```scala val x = if (a < b) { a } else { b } ``` + {% endtab %} {% tab 'Scala 3' for=if-else-expression %} + ```scala val x = if a < b then a else b ``` + {% endtab %} {% endtabs %} @@ -77,21 +85,25 @@ This example shows how to print every element in a `List`: {% tabs for-loop class=tabs-scala-version %} {% tab 'Scala 2' for=for-loop %} + ```scala val ints = List(1, 2, 3, 4, 5) for (i <- ints) println(i) ``` + > The old syntax in Scala 2 `for` structure. {% endtab %} {% tab 'Scala 3' for=for-loop %} + ```scala val ints = List(1, 2, 3, 4, 5) for i <- ints do println(i) ``` + > The code `i <- ints` is referred to as a _generator_, and the code that follows the `do` keyword is the _body_ of the loop. {% endtab %} @@ -107,13 +119,16 @@ This example prints all of the numbers in `ints` that are greater than `2`: {% tabs for-guards class=tabs-scala-version %} {% tab 'Scala 2' for=for-guards %} + ```scala for ( i <- ints if i > 2) println(i) ``` + {% endtab %} {% tab 'Scala 3' for=for-guards %} + ```scala for i <- ints @@ -121,6 +136,7 @@ for do println(i) ``` + {% endtab %} {% endtabs %} @@ -130,14 +146,17 @@ However, it also has two guards, so the only time the print statement is called {% tabs for-guards-multi class=tabs-scala-version %} {% tab 'Scala 2' for=for-guards-multi %} + ```scala for ( i <- 1 to 3 if i == 2; j <- 'a' to 'c' if j == 'b' ) println(s"i = $i, j = $j") // prints: "i = 2, j = b" ``` + {% endtab %} {% tab 'Scala 3' for=for-guards-multi %} + ```scala for i <- 1 to 3 @@ -147,6 +166,7 @@ for do println(s"i = $i, j = $j") // prints: "i = 2, j = b" ``` + {% endtab %} {% endtabs %} @@ -159,17 +179,21 @@ Using the same `ints` list as the previous example, this code creates a new list {% tabs for-expression_1 class=tabs-scala-version %} {% tab 'Scala 2' for=for-expression_1 %} + ```` scala> val doubles = for (i <- ints) yield i * 2 val doubles: List[Int] = List(2, 4, 6, 8, 10) ```` + {% endtab %} {% tab 'Scala 3' for=for-expression_1 %} + ```` scala> val doubles = for i <- ints yield i * 2 val doubles: List[Int] = List(2, 4, 6, 8, 10) ```` + {% endtab %} {% endtabs %} @@ -177,20 +201,24 @@ Scala’s control structure syntax is flexible, and that `for` expression can be {% tabs for-expressioni_2 class=tabs-scala-version %} {% tab 'Scala 2' for=for-expressioni_2 %} + ```scala val doubles = for (i <- ints) yield i * 2 val doubles = for (i <- ints) yield (i * 2) val doubles = for { i <- ints } yield (i * 2) ``` + {% endtab %} {% tab 'Scala 3' for=for-expressioni_2 %} + ```scala val doubles = for i <- ints yield i * 2 // style shown above val doubles = for (i <- ints) yield i * 2 val doubles = for (i <- ints) yield (i * 2) val doubles = for { i <- ints } yield (i * 2) ``` + {% endtab %} {% endtabs %} @@ -198,17 +226,21 @@ This example shows how to capitalize the first character in each string in the l {% tabs for-expressioni_3 class=tabs-scala-version %} {% tab 'Scala 2' for=for-expressioni_3 %} + ```scala val names = List("chris", "ed", "maurice") val capNames = for ( name <- names ) yield name.capitalize ``` + {% endtab %} {% tab 'Scala 3' for=for-expressioni_3 %} + ```scala val names = List("chris", "ed", "maurice") val capNames = for name <- names yield name.capitalize ``` + {% endtab %} {% endtabs %} @@ -216,6 +248,7 @@ Finally, this `for` expression iterates over a list of strings, and returns the {% tabs for-expressioni_4 class=tabs-scala-version %} {% tab 'Scala 2' for=for-expressioni_4 %} + ```scala val fruits = List("apple", "banana", "lime", "orange") @@ -224,9 +257,11 @@ val fruitLengths = for ( f <- fruits if f.length > 4 ) // fruitLengths: List[Int] = List(5, 6, 6) ``` + {% endtab %} {% tab 'Scala 3' for=for-expressioni_4 %} + ```scala val fruits = List("apple", "banana", "lime", "orange") @@ -240,6 +275,7 @@ yield // fruitLengths: List[Int] = List(5, 6, 6) ``` + {% endtab %} {% endtabs %} @@ -251,6 +287,7 @@ Scala has a `match` expression, which in its most basic use is like a Java `swit {% tabs match class=tabs-scala-version %} {% tab 'Scala 2' for=match %} + ```scala val i = 1 @@ -261,9 +298,11 @@ i match { case _ => println("other") } ``` + {% endtab %} {% tab 'Scala 3' for=match %} + ```scala val i = 1 @@ -273,6 +312,7 @@ i match case 2 => println("two") case _ => println("other") ``` + {% endtab %} {% endtabs %} @@ -280,6 +320,7 @@ However, `match` really is an expression, meaning that it returns a result based {% tabs match-expression_1 class=tabs-scala-version %} {% tab 'Scala 2' for=match-expression_1 %} + ```scala val result = i match { case 1 => "one" @@ -287,15 +328,18 @@ val result = i match { case _ => "other" } ``` + {% endtab %} {% tab 'Scala 3' for=match-expression_1 %} + ```scala val result = i match case 1 => "one" case 2 => "two" case _ => "other" ``` + {% endtab %} {% endtabs %} @@ -303,6 +347,7 @@ val result = i match {% tabs match-expression_2 class=tabs-scala-version %} {% tab 'Scala 2' for=match-expression_2 %} + ```scala val p = Person("Fred") @@ -317,9 +362,11 @@ p match { case _ => println("Watch the Flintstones!") } ``` + {% endtab %} {% tab 'Scala 3' for=match-expression_2 %} + ```scala val p = Person("Fred") @@ -333,6 +380,7 @@ p match case _ => println("Watch the Flintstones!") ``` + {% endtab %} {% endtabs %} @@ -341,6 +389,7 @@ This example shows (a) how to use a `match` expression as the body of a method, {% tabs match-expression_3 class=tabs-scala-version %} {% tab 'Scala 3 only' for=match-expression_3 %} + ```scala // getClassAsString is a method that takes a single argument of any type. def getClassAsString(x: Matchable): String = x match @@ -355,6 +404,7 @@ getClassAsString(1) // Int getClassAsString("hello") // 'hello' is a String getClassAsString(List(1, 2, 3)) // List ``` + {% endtab %} {% endtabs %} @@ -373,6 +423,7 @@ It’s similar to Java, but its syntax is consistent with `match` expressions: {% tabs try class=tabs-scala-version %} {% tab 'Scala 2' for=try %} + ```scala try { writeTextToFile(text) @@ -383,9 +434,11 @@ try { println("Clean up your resources here.") } ``` + {% endtab %} {% tab 'Scala 3' for=try %} + ```scala try writeTextToFile(text) @@ -395,6 +448,7 @@ catch finally println("Clean up your resources here.") ``` + {% endtab %} {% endtabs %} @@ -405,15 +459,19 @@ It’s one-line syntax looks like this: {% tabs while_1 class=tabs-scala-version %} {% tab 'Scala 2' for=while_1 %} + ```scala while ( x >= 0 ) { x = f(x) } ``` + {% endtab %} {% tab 'Scala 3' for=while_1 %} + ```scala while x >= 0 do x = f(x) ``` + {% endtab %} {% endtabs %} @@ -423,6 +481,7 @@ The `while` loop multiline syntax looks like this: {% tabs while_2 class=tabs-scala-version %} {% tab 'Scala 2' for=while_2 %} + ```scala var x = 1 @@ -431,9 +490,11 @@ while (x < 3) { x += 1 } ``` + {% endtab %} {% tab 'Scala 3' for=while_2 %} + ```scala var x = 1 @@ -443,6 +504,7 @@ do println(x) x += 1 ``` + {% endtab %} {% endtabs %} From f817f64bdeb027b957c486169db598d57aea8e34 Mon Sep 17 00:00:00 2001 From: Ben Luo Date: Wed, 12 Oct 2022 20:18:03 +0800 Subject: [PATCH 3/4] correct "Scala 3 Only" tab. --- _overviews/scala3-book/taste-control-structures.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_overviews/scala3-book/taste-control-structures.md b/_overviews/scala3-book/taste-control-structures.md index d1668fdf4e..cd56afd82d 100644 --- a/_overviews/scala3-book/taste-control-structures.md +++ b/_overviews/scala3-book/taste-control-structures.md @@ -387,8 +387,8 @@ p match In fact, a `match` expression can be used to test a variable against many different types of patterns. This example shows (a) how to use a `match` expression as the body of a method, and (b) how to match all the different types shown: -{% tabs match-expression_3 class=tabs-scala-version %} -{% tab 'Scala 3 only' for=match-expression_3 %} +{% tabs match-expression_3 %} +{% tab 'Scala 3 Only' for=match-expression_3 %} ```scala // getClassAsString is a method that takes a single argument of any type. From d7ed15c858c415c6ef2978a6e6424b964a6e2006 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Tue, 18 Oct 2022 15:36:40 +0200 Subject: [PATCH 4/4] update formatting --- .../scala3-book/taste-control-structures.md | 56 +++++++++++++------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/_overviews/scala3-book/taste-control-structures.md b/_overviews/scala3-book/taste-control-structures.md index cd56afd82d..5a61bacb58 100644 --- a/_overviews/scala3-book/taste-control-structures.md +++ b/_overviews/scala3-book/taste-control-structures.md @@ -92,7 +92,7 @@ val ints = List(1, 2, 3, 4, 5) for (i <- ints) println(i) ``` -> The old syntax in Scala 2 `for` structure. +> The code `i <- ints` is referred to as a _generator_, and the code that follows the closing parentheses of the generator is the _body_ of the loop. {% endtab %} @@ -109,8 +109,6 @@ for i <- ints do println(i) {% endtab %} {% endtabs %} -Again, note the usage of parentheses and the new `for`-`do` in Scala 3. - ### Guards You can also use one or more `if` expressions inside a `for` loop. @@ -121,7 +119,7 @@ This example prints all of the numbers in `ints` that are greater than `2`: {% tab 'Scala 2' for=for-guards %} ```scala -for ( i <- ints if i > 2) +for (i <- ints if i > 2) println(i) ``` @@ -148,9 +146,14 @@ However, it also has two guards, so the only time the print statement is called {% tab 'Scala 2' for=for-guards-multi %} ```scala -for ( i <- 1 to 3 if i == 2; - j <- 'a' to 'c' if j == 'b' ) +for { + i <- 1 to 3 + j <- 'a' to 'c' + if i == 2 + if j == 'b' +} { println(s"i = $i, j = $j") // prints: "i = 2, j = b" +} ``` {% endtab %} @@ -229,7 +232,7 @@ This example shows how to capitalize the first character in each string in the l ```scala val names = List("chris", "ed", "maurice") -val capNames = for ( name <- names ) yield name.capitalize +val capNames = for (name <- names) yield name.capitalize ``` {% endtab %} @@ -252,8 +255,8 @@ Finally, this `for` expression iterates over a list of strings, and returns the ```scala val fruits = List("apple", "banana", "lime", "orange") -val fruitLengths = for ( f <- fruits if f.length > 4 ) - yield f.length +val fruitLengths = + for (f <- fruits if f.length > 4) yield f.length // fruitLengths: List[Int] = List(5, 6, 6) ``` @@ -387,17 +390,18 @@ p match In fact, a `match` expression can be used to test a variable against many different types of patterns. This example shows (a) how to use a `match` expression as the body of a method, and (b) how to match all the different types shown: -{% tabs match-expression_3 %} -{% tab 'Scala 3 Only' for=match-expression_3 %} +{% tabs match-expression_3 class=tabs-scala-version %} +{% tab 'Scala 2' for=match-expression_3 %} ```scala // getClassAsString is a method that takes a single argument of any type. -def getClassAsString(x: Matchable): String = x match +def getClassAsString(x: Any): String = x match { case s: String => s"'$s' is a String" case i: Int => "Int" case d: Double => "Double" case l: List[_] => "List" case _ => "Unknown" +} // examples getClassAsString(1) // Int @@ -405,13 +409,34 @@ getClassAsString("hello") // 'hello' is a String getClassAsString(List(1, 2, 3)) // List ``` +Because the method `getClassAsString` takes a parameter value of type `Any`, it can be decomposed by any kind of +pattern. + {% endtab %} -{% endtabs %} +{% tab 'Scala 3' for=match-expression_3 %} + +```scala +// getClassAsString is a method that takes a single argument of any type. +def getClassAsString(x: Matchable): String = x match + case s: String => s"'$s' is a String" + case i: Int => "Int" + case d: Double => "Double" + case l: List[?] => "List" + case _ => "Unknown" + +// examples +getClassAsString(1) // Int +getClassAsString("hello") // 'hello' is a String +getClassAsString(List(1, 2, 3)) // List +``` The method `getClassAsString` takes as a parameter a value of type [Matchable]({{ site.scala3ref }}/other-new-features/matchable.html), which can be any type supporting pattern matching (some types don’t support pattern matching because this could break encapsulation). +{% endtab %} +{% endtabs %} + There’s _much_ more to pattern matching in Scala. Patterns can be nested, results of patterns can be bound, and pattern matching can even be user-defined. See the pattern matching examples in the [Control Structures chapter][control] for more details. @@ -461,7 +486,7 @@ It’s one-line syntax looks like this: {% tab 'Scala 2' for=while_1 %} ```scala -while ( x >= 0 ) { x = f(x) } +while (x >= 0) { x = f(x) } ``` {% endtab %} @@ -471,12 +496,11 @@ while ( x >= 0 ) { x = f(x) } ```scala while x >= 0 do x = f(x) ``` +Scala 3 still supports the Scala 2 syntax for the sake of compatibility. {% endtab %} {% endtabs %} -Scala 3 still supports the Scala 2 syntax for the sake of compatibility. - The `while` loop multiline syntax looks like this: {% tabs while_2 class=tabs-scala-version %}