Difference between revisions of "Scala"
Jump to navigation
Jump to search
PeterHarding (talk | contribs) (Created page with "=Scala Notes= * https://en.wikipedia.org/wiki/Scala_(programming_language) Category:Scala") |
PeterHarding (talk | contribs) |
||
| (2 intermediate revisions by the same user not shown) | |||
| Line 2: | Line 2: | ||
* https://en.wikipedia.org/wiki/Scala_(programming_language) | * https://en.wikipedia.org/wiki/Scala_(programming_language) | ||
= Use of '_' = | |||
From - https://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala | |||
<pre> | |||
import scala._ // Wild card -- all of Scala is imported | |||
import scala.{ Predef => _, _ } // Exception, everything except Predef | |||
def f[M[_]] // Higher kinded type parameter | |||
def f(m: M[_]) // Existential type | |||
_ + _ // Anonymous function placeholder parameter | |||
m _ // Eta expansion of method into method value | |||
m(_) // Partial function application | |||
_ => 5 // Discarded parameter | |||
case _ => // Wild card pattern -- matches anything | |||
val (a, _) = (1, 2) // same thing | |||
for (_ <- 1 to 10) // same thing | |||
f(xs: _*) // Sequence xs is passed as multiple parameters to f(ys: T*) | |||
case Seq(xs @ _*) // Identifier xs is bound to the whole matched sequence | |||
var i: Int = _ // Initialization to the default value | |||
def abc_<>! // An underscore must separate alphanumerics from symbols on identifiers | |||
t._2 // Part of a method name, such as tuple getters | |||
1_000_000 // Numeric literal separator (Scala 2.13+) | |||
</pre> | |||
So... | |||
==Existential types== | |||
def foo(l: List[Option[_]]) = ... | |||
==Higher kinded type parameters== | |||
case class A[K[_],T](a: K[T]) | |||
==Ignored variables== | |||
val _ = 5 | |||
==Ignored parameters== | |||
List(1, 2, 3) foreach { _ => println("Hi") } | |||
==Ignored names of self types== | |||
trait MySeq { _: Seq[_] => } | |||
==Wildcard patterns== | |||
Some(5) match { case Some(_) => println("Yes") } | |||
==Wildcard patterns in interpolations== | |||
"abc" match { case s"a$_c" => } | |||
==Sequence wildcard in patterns== | |||
C(1, 2, 3) match { case C(vs @ _*) => vs.foreach(f(_)) } | |||
==Wildcard imports== | |||
import java.util._ | |||
==Hiding imports== | |||
import java.util.{ArrayList => _, _} | |||
==Joining letters to operators== | |||
def bang_!(x: Int) = 5 | |||
==Assignment operators== | |||
def foo_=(x: Int) { ... } | |||
==Placeholder syntax== | |||
List(1, 2, 3) map (_ + 2) | |||
==Method values== | |||
List(1, 2, 3) foreach println _ | |||
==Converting call-by-name parameters to functions== | |||
def toFunction(callByName: => Int): () => Int = callByName _ | |||
==Default initializer== | |||
var x: String = _ // unloved syntax may be eliminated | |||
=Other= | |||
* https://alvinalexander.com/scala/how-to-use-scala-match-expression-like-switch-case-statement/ | |||
=Match Expressions= | |||
* https://docs.scala-lang.org/overviews/scala-book/match-expressions.html | |||
<pre> | |||
def getClassAsString(x: Any): String = x match { | |||
case s: String => s + " is a String" | |||
case i: Int => "Int" | |||
case f: Float => "Float" | |||
case l: List[_] => "List" | |||
case p: Person => "Person" | |||
case _ => "Unknown" | |||
} | |||
</pre> | |||
<pre> | |||
def isTrue(a: Any) = a match { | |||
case 0 | "" => false | |||
case _ => true | |||
} | |||
</pre> | |||
<pre> | |||
// Version 1 - compiles to a tableswitch | |||
import scala.annotation.switch | |||
class SwitchDemo { | |||
val i = 1 | |||
val x = (i: @switch) match { | |||
case 1 => "One" | |||
case 2 => "Two" | |||
case _ => "Other" | |||
} | |||
} | |||
</pre> | |||
<pre> | |||
expr match { | |||
case List(1,_,_) => "A List with three elements" | |||
case List(_ *) => "A List with zero or more elements" | |||
case Map(_,_) => "A Map with any Key and Value type" | |||
case _ => "Anythiong else" | |||
} | |||
</pre> | |||
=Getters and Setters= | |||
According to the Scala docs: | |||
Scala does not follow the Java convention of prepending set/get to mutator and accessor methods (respectively). Instead, the following conventions are used: | |||
* For accessors of properties, the name of the method should be the name of the property. | |||
* In some instances, it is acceptable to prepend “is” on a boolean accessor (e.g. isEmpty). This should only be the case when no corresponding mutator is provided. | |||
* For mutators, the name of the method should be the name of the property with “_=” appended. | |||
So: | |||
<pre> | |||
class Foo { | |||
def bar = ... | |||
def bar_=(bar: Bar) { | |||
... | |||
} | |||
def isBaz = ... | |||
} | |||
</pre> | |||
<pre> | |||
val nums = List(1,2,3,4,5,6,7,8,9) | |||
nums filter (_ % 2 == 0) | |||
nums reduce (_ + _) | |||
nums.exists (_ > 5) | |||
nums.takeWhile(_ < 8) | |||
</pre> | |||
As used in Swift for un-named or unused values: | |||
<pre> | |||
def getProps = { | |||
Config.getHost, Config.getPort, Config.getIp, Config.getMask | |||
} | |||
val (host, port, ignore1, ignore2) = getProps | |||
val (host, port, _, _) = getProps | |||
</pre> | |||
=Types= | |||
<pre> | |||
type StringMatcher = String => (String => Boolean) | |||
def starts: StringMatcher = (prefix:String) => _ startsWith prefix | |||
...or... | |||
def starts: StringMatcher = (prefix:String) => (s) => s startsWith prefix | |||
</pre> | |||
=Generating Random Strings= | |||
One liner: | |||
<pre> | |||
Random.alphanumeric.take(10).mkString | |||
</pre> | |||
From - https://alvinalexander.com/scala/creating-random-strings-in-scala/ | |||
<pre> | |||
import scala.annotation.tailrec | |||
/** | |||
* Examples of different ways to write "random string" methods in Scala. | |||
* See the main method for examples of how each method is called. | |||
* Created by Alvin Alexander, https://alvinalexander.com | |||
*/ | |||
object RandomStringExamples { | |||
def main(args: Array[String]) { | |||
println("1: " + randomString(10)) | |||
println("2: " + randomStringArray(10)) | |||
println("3: " + randomStringRecursive(10).mkString) | |||
println("3: " + randomStringRecursive2(10).mkString) | |||
println("4: " + randomStringTailRecursive(10, Nil).mkString) | |||
println("5: " + randomStringRecursive2Wrapper(10)) | |||
println("6: " + randomAlphaNumericString(10)) | |||
println("6: " + randomAlphaNumericString(10)) | |||
println("6: " + randomAlphaNumericString(10)) | |||
println("x2: " + x2(10, ('a' to 'z') ++ ('A' to 'Z'))) | |||
} | |||
// 1 - a java-esque approach | |||
def randomString(length: Int) = { | |||
val r = new scala.util.Random | |||
val sb = new StringBuilder | |||
for (i <- 1 to length) { | |||
sb.append(r.nextPrintableChar) | |||
} | |||
sb.toString | |||
} | |||
// 2 - similar to #1, but using an array | |||
def randomStringUsingArray(length: Int): String = { | |||
val r = new scala.util.Random | |||
val a = new Array[Char](length) | |||
val sb = new StringBuilder | |||
for (i <- 0 to length-1) { | |||
a(i) = r.nextPrintableChar | |||
} | |||
a.mkString | |||
} | |||
// 3 - recursive, but not tail-recursive | |||
def randomStringRecursive(n: Int): List[Char] = { | |||
n match { | |||
case 1 => List(util.Random.nextPrintableChar) | |||
case _ => List(util.Random.nextPrintableChar) ++ randomStringRecursive(n-1) | |||
} | |||
} | |||
// 3b - recursive, but not tail-recursive | |||
def randomStringRecursive2(n: Int): String = { | |||
n match { | |||
case 1 => util.Random.nextPrintableChar.toString | |||
case _ => util.Random.nextPrintableChar.toString ++ randomStringRecursive2(n-1).toString | |||
} | |||
} | |||
// 4 - tail recursive, no wrapper | |||
@tailrec | |||
def randomStringTailRecursive(n: Int, list: List[Char]):List[Char] = { | |||
if (n == 1) util.Random.nextPrintableChar :: list | |||
else randomStringTailRecursive(n-1, util.Random.nextPrintableChar :: list) | |||
} | |||
// 5 - a wrapper around the tail-recursive approach | |||
def randomStringRecursive2Wrapper(n: Int): String = { | |||
randomStringTailRecursive(n, Nil).mkString | |||
} | |||
// 6 - random alphanumeric | |||
def randomAlphaNumericString(length: Int): String = { | |||
val chars = ('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9') | |||
randomStringFromCharList(length, chars) | |||
} | |||
// 7 - random alpha | |||
def randomAlpha(length: Int): String = { | |||
val chars = ('a' to 'z') ++ ('A' to 'Z') | |||
randomStringFromCharList(length, chars) | |||
} | |||
// used by #6 and #7 | |||
def randomStringFromCharList(length: Int, chars: Seq[Char]): String = { | |||
val sb = new StringBuilder | |||
for (i <- 1 to length) { | |||
val randomNum = util.Random.nextInt(chars.length) | |||
sb.append(chars(randomNum)) | |||
} | |||
sb.toString | |||
} | |||
def x(length: Int, chars: Seq[Char]): String = { | |||
val list = List.range(1, length) | |||
val arr = new Array[Char](length) | |||
list.foreach{ e => arr(e) = chars(util.Random.nextInt(chars.length)) } | |||
list.mkString | |||
} | |||
// create a fake list so i can use map (or flatMap) | |||
def x2(length: Int, chars: Seq[Char]): String = { | |||
val tmpList = List.range(0, length) | |||
val charList = tmpList.map{ e => chars(util.Random.nextInt(chars.length)) } | |||
return charList.mkString | |||
} | |||
} | |||
</pre> | |||
<pre> | |||
</pre> | |||
[[Category:Scala]] | [[Category:Scala]] | ||
Latest revision as of 10:49, 13 May 2021
Scala Notes
Use of '_'
From - https://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala
import scala._ // Wild card -- all of Scala is imported
import scala.{ Predef => _, _ } // Exception, everything except Predef
def f[M[_]] // Higher kinded type parameter
def f(m: M[_]) // Existential type
_ + _ // Anonymous function placeholder parameter
m _ // Eta expansion of method into method value
m(_) // Partial function application
_ => 5 // Discarded parameter
case _ => // Wild card pattern -- matches anything
val (a, _) = (1, 2) // same thing
for (_ <- 1 to 10) // same thing
f(xs: _*) // Sequence xs is passed as multiple parameters to f(ys: T*)
case Seq(xs @ _*) // Identifier xs is bound to the whole matched sequence
var i: Int = _ // Initialization to the default value
def abc_<>! // An underscore must separate alphanumerics from symbols on identifiers
t._2 // Part of a method name, such as tuple getters
1_000_000 // Numeric literal separator (Scala 2.13+)
So...
Existential types
def foo(l: List[Option[_]]) = ...
Higher kinded type parameters
case class A[K[_],T](a: K[T])
Ignored variables
val _ = 5
Ignored parameters
List(1, 2, 3) foreach { _ => println("Hi") }
Ignored names of self types
trait MySeq { _: Seq[_] => }
Wildcard patterns
Some(5) match { case Some(_) => println("Yes") }
Wildcard patterns in interpolations
"abc" match { case s"a$_c" => }
Sequence wildcard in patterns
C(1, 2, 3) match { case C(vs @ _*) => vs.foreach(f(_)) }
Wildcard imports
import java.util._
Hiding imports
import java.util.{ArrayList => _, _}
Joining letters to operators
def bang_!(x: Int) = 5
Assignment operators
def foo_=(x: Int) { ... }
Placeholder syntax
List(1, 2, 3) map (_ + 2)
Method values
List(1, 2, 3) foreach println _
Converting call-by-name parameters to functions
def toFunction(callByName: => Int): () => Int = callByName _
Default initializer
var x: String = _ // unloved syntax may be eliminated
Other
Match Expressions
def getClassAsString(x: Any): String = x match {
case s: String => s + " is a String"
case i: Int => "Int"
case f: Float => "Float"
case l: List[_] => "List"
case p: Person => "Person"
case _ => "Unknown"
}
def isTrue(a: Any) = a match {
case 0 | "" => false
case _ => true
}
// Version 1 - compiles to a tableswitch
import scala.annotation.switch
class SwitchDemo {
val i = 1
val x = (i: @switch) match {
case 1 => "One"
case 2 => "Two"
case _ => "Other"
}
}
expr match {
case List(1,_,_) => "A List with three elements"
case List(_ *) => "A List with zero or more elements"
case Map(_,_) => "A Map with any Key and Value type"
case _ => "Anythiong else"
}
Getters and Setters
According to the Scala docs:
Scala does not follow the Java convention of prepending set/get to mutator and accessor methods (respectively). Instead, the following conventions are used:
- For accessors of properties, the name of the method should be the name of the property.
- In some instances, it is acceptable to prepend “is” on a boolean accessor (e.g. isEmpty). This should only be the case when no corresponding mutator is provided.
- For mutators, the name of the method should be the name of the property with “_=” appended.
So:
class Foo {
def bar = ...
def bar_=(bar: Bar) {
...
}
def isBaz = ...
}
val nums = List(1,2,3,4,5,6,7,8,9) nums filter (_ % 2 == 0) nums reduce (_ + _) nums.exists (_ > 5) nums.takeWhile(_ < 8)
As used in Swift for un-named or unused values:
def getProps = {
Config.getHost, Config.getPort, Config.getIp, Config.getMask
}
val (host, port, ignore1, ignore2) = getProps
val (host, port, _, _) = getProps
Types
type StringMatcher = String => (String => Boolean) def starts: StringMatcher = (prefix:String) => _ startsWith prefix ...or... def starts: StringMatcher = (prefix:String) => (s) => s startsWith prefix
Generating Random Strings
One liner:
Random.alphanumeric.take(10).mkString
From - https://alvinalexander.com/scala/creating-random-strings-in-scala/
import scala.annotation.tailrec
/**
* Examples of different ways to write "random string" methods in Scala.
* See the main method for examples of how each method is called.
* Created by Alvin Alexander, https://alvinalexander.com
*/
object RandomStringExamples {
def main(args: Array[String]) {
println("1: " + randomString(10))
println("2: " + randomStringArray(10))
println("3: " + randomStringRecursive(10).mkString)
println("3: " + randomStringRecursive2(10).mkString)
println("4: " + randomStringTailRecursive(10, Nil).mkString)
println("5: " + randomStringRecursive2Wrapper(10))
println("6: " + randomAlphaNumericString(10))
println("6: " + randomAlphaNumericString(10))
println("6: " + randomAlphaNumericString(10))
println("x2: " + x2(10, ('a' to 'z') ++ ('A' to 'Z')))
}
// 1 - a java-esque approach
def randomString(length: Int) = {
val r = new scala.util.Random
val sb = new StringBuilder
for (i <- 1 to length) {
sb.append(r.nextPrintableChar)
}
sb.toString
}
// 2 - similar to #1, but using an array
def randomStringUsingArray(length: Int): String = {
val r = new scala.util.Random
val a = new Array[Char](length)
val sb = new StringBuilder
for (i <- 0 to length-1) {
a(i) = r.nextPrintableChar
}
a.mkString
}
// 3 - recursive, but not tail-recursive
def randomStringRecursive(n: Int): List[Char] = {
n match {
case 1 => List(util.Random.nextPrintableChar)
case _ => List(util.Random.nextPrintableChar) ++ randomStringRecursive(n-1)
}
}
// 3b - recursive, but not tail-recursive
def randomStringRecursive2(n: Int): String = {
n match {
case 1 => util.Random.nextPrintableChar.toString
case _ => util.Random.nextPrintableChar.toString ++ randomStringRecursive2(n-1).toString
}
}
// 4 - tail recursive, no wrapper
@tailrec
def randomStringTailRecursive(n: Int, list: List[Char]):List[Char] = {
if (n == 1) util.Random.nextPrintableChar :: list
else randomStringTailRecursive(n-1, util.Random.nextPrintableChar :: list)
}
// 5 - a wrapper around the tail-recursive approach
def randomStringRecursive2Wrapper(n: Int): String = {
randomStringTailRecursive(n, Nil).mkString
}
// 6 - random alphanumeric
def randomAlphaNumericString(length: Int): String = {
val chars = ('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9')
randomStringFromCharList(length, chars)
}
// 7 - random alpha
def randomAlpha(length: Int): String = {
val chars = ('a' to 'z') ++ ('A' to 'Z')
randomStringFromCharList(length, chars)
}
// used by #6 and #7
def randomStringFromCharList(length: Int, chars: Seq[Char]): String = {
val sb = new StringBuilder
for (i <- 1 to length) {
val randomNum = util.Random.nextInt(chars.length)
sb.append(chars(randomNum))
}
sb.toString
}
def x(length: Int, chars: Seq[Char]): String = {
val list = List.range(1, length)
val arr = new Array[Char](length)
list.foreach{ e => arr(e) = chars(util.Random.nextInt(chars.length)) }
list.mkString
}
// create a fake list so i can use map (or flatMap)
def x2(length: Int, chars: Seq[Char]): String = {
val tmpList = List.range(0, length)
val charList = tmpList.map{ e => chars(util.Random.nextInt(chars.length)) }
return charList.mkString
}
}