[TOC]
1.1 INTRODUCTION
Scala is a multi paradigm programming language. The original intention of its design is to integrate various features of object-oriented programming and functional programming. Scala runs on the Java platform (Java virtual machine) and is compatible with existing Java programs. It can also run in Java ME in CLDC configuration. At present, there is another. NET platform, but the update of this version is a little behind. Scala's compilation model (independent compilation, dynamic class loading) is the same as Java and C ා, so Scala code can call Java class library (for. NET implementation, it can call. NET class library).
1.2 scala installation and configuration
scala runs on the JVM, so you need to install jdk first. See the previous article for the installation process. First come to < Http://www.scala-lang.org/ > download the scala installation package. The version I use here is scala2.11.8. windows installation is basically a little bit, so I won't show it here. After installation, the PATH environment variable is configured by default.
If you install it on Linux, download the. tgz package for use, and extract it to the specified directory. This is basically how to configure the PATH environment variable. Finally, enter Scala at the command line. Entering the scala command line successfully means success (just like installing jdk in Linux)
It should be noted that in scala, any data is an object, and some methods can be called through the data itself. In java, only after the data is assigned to a reference variable can the method be called through the reference variable. as
"1".toInt(), which can run in scala, can't run in java in a way like this2.1 common data types
2.1.1 value type:
Byte,Short,Int,Long,Float,Double Byte: 8-bit signed number, from - 128 to 127 Short: 16 bit signed data, from - 32768 to 32767 Int: 32-bit signed data Long: 64 bit signed data Example: define an Int variable in the scala command line val a:Byte = 10 a+10 Get: res9: Int = 20 res9 here is the name of the newly generated variable2.1.2 character type
Char and String, the former is single character, the latter is String For strings, you can perform interpolation operations in scala, such as: scala> val a="king" a: String = king scala> s"my name is $" res1: String = my name is king Note: there is an s in front; it is equivalent to executing "my name is" + S12.1.3 Unit type
Equivalent to the void type in java, commonly used for the return value type of function methods2.1.4 Nothing type
Generally, during execution, the type of exception generated is nothing2.2 declaration and use of variables
var Variable name: type=value val Variable name: type=value //The type can be omitted, and scala will automatically deduce the type of variable according to the type of value. //Example: var a:Int=8 var and val The difference is: val The memory address that the reference points to cannot be changed, but its contents can be changed. var The reference points to a variable memory address. And when it is defined, it must be initialized //Such as: scala> val a=2 a: Int = 2 scala> a=3 <console>:12: error: reassignment to val a=3 ^ scala> var b=2 b: Int = 2 scala> b=3 b: Int = 3 //As you can see, there's no way to reassign a
2.3 preliminary use of functions
2.3.1 scala built-in functions
Scala has many built-in functions, which can be used directly, such as various mathematical functions under scala.math package
import scala.math._ Import math All functions under scala> import scala.math._ import scala.math._ scala> max(2,3) res0: Int = 3
2.3.2 user defined function
def Function name([Parameter name: parameter type]*) : return type = {} //Example: 1,Summation scala> def sum(x:Int,y:Int) : Int = x+y sum: (x: Int, y: Int)Int scala> sum(10,20) res4: Int = 30 scala> var a = sum(10,20) a: Int = 30 2,Factoring, recursion scala> def myFactor(x:Int) : Int = { | //Realization | if(x<=1) | 1 | else | x*myFactor(x-1) | } myFactor: (x: Int)Int scala> myFactor(3) res5: Int = 6 //Note: if there is no return statement, the last sentence of the function is the return value of the function. //The function above has branches. Both 1 and x*myFactor(x-1) may be the last sentence of the function.
2.4 scala conditional statements and loop statements
2.4.1 condition judgment statement if/else:
if (Judgement condition) {} else if (Judgement condition) {} else {}
2.4.2 loop statement:
for cycle
//Define a list to facilitate the operation of the for loop var list = List("Mary","Tom","Mike") println("-----for Cycle the first way-------") for( s <- list) println(s) // < represents the extractor in scala, extracts every element in the list, and assigns it to s println("-----for The second writing method of circulation-------") //The length of the printed name is greater than 3 plus judgment. You can add judgment for{ s <- list if(s.length > 3) } println(s) println("-----for The third writing method of circulation-------") //Print name length less than or equal to 3 plus judgment for(s <- list if s.length <= 3 ) println(s) println("-----for The fourth writing method of circulation-------") //Use the yield keyword to generate a new set //Capitalize each element in the list and return a new collection. var newList = for{ s <- list s1 = s.toUpperCase //Capitalize your name } yield (s1) //Use yield to change the processed elements into a new collection for( s <- newList) println(s)
while loop:
println("-----while Cyclic writing-------") //Define a loop variable var i = 0 while(i < list.length){ println(list(i)) //Self increment //i + + is not feasible in scala i += 1 } println("-----do while Cyclic writing-------") //Define loop variables var j = 0 do{ println(list(j)) j+=1 } while (j < list.length)
Iteration of foreach function:
println("-----foreach usage -----") list.foreach(println) / / equivalent to for (s < - list) println (s) /** *foreach description * *foreach is equivalent to a loop *list.foreach(println) uses higher-order functions (functional programming) * *There is also a loop map *The difference between foreach and map: *foreach has no return value, map has a return value *Similar in spark. */ The second foreach method: list.foreach{ case xxxxx } Directly use case internally for pattern matching2.4.3 nested loops and break statements
/** * Topic: judge how many prime numbers are between 101-200 * * Program analysis: * How to judge prime number: * If a number can be divided by an integer, it means that the number is not a prime number, but a prime number * Example: 101 2 ~ root (101) * * Program implementation method: * Define a two-tier cycle * First floor 101-200 * 2nd floor 2 - root sign (1st floor) * If a judgment can be divided by an integer, it is not a prime number * */ println("-----loop nesting-------") var count : Int = 0 //Save the number of prime numbers var index_outer : Int = 0 //Outer loop variable var index_inner : Int = 0 //Inner loop variable //Until statement, x until y means x to y, excluding y for (index_outer <- 101 until 200 ){ var b = false //Mark whether it can be divisible breakable{ index_inner = 2 while (index_inner <= sqrt(index_outer)){ if(index_outer % index_inner == 0){ //Can be divisible b = true break } index_inner += 1 } } if (!b){ count +=1 } } println("The number is: " + count)
break usage:
Include the statement block to be broken with breakable {}, and then use the break statement to break it2.4.4 nested loop for bubble sorting
/** * Bubble sort * https://www.cnblogs.com/morethink/p/8419151.html#%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F * * Algorithm analysis: * 1,Compare adjacent elements and swap positions if the first is larger than the second * 2,Do the same for each pair of adjacent elements. After this step is completed, the final element will be the maximum number * 3,Repeat for all elements. * * Program analysis: * 1,Two level circulation * 2,Number of outer loop control comparisons * 3,The inner loop controls the position of arrival, that is, the position where the comparison ends */ println("------------Bubble sort--------------") var listSort = LinkedList(3,9,1,6,5,7,10,2,4) var startIndex:Int = 0 var secondIndex:Int = 0 var tmp:Int = 0 for (startIndex <- 0 until(listSort.length - 1)) { for (secondIndex <- startIndex + 1 until(listSort.length)) { if (listSort(startIndex) > listSort(secondIndex)) { tmp = listSort(startIndex) listSort(startIndex) = listSort(secondIndex) listSort(secondIndex) = tmp } } }
2.5 parameters of scala function
2.5.1 evaluation strategy of function parameters
call by value:
Evaluate function arguments once Example: def test(x:Int)call by name:
Function arguments are evaluated only when they are used inside the function body Example: def test(x:=>Int) Pay attention to the symbols between variable name and type. There are more = > symbols. Don't miss themMaybe it's not clear. Let's take a look at an example
scala> def test1(x:Int,y:Int) : Int = x+x test1: (x: Int, y: Int)Int scala> test1(3+4,8) res0: Int = 14 scala> def test2(x: => Int,y: => Int) : Int = x+x test2: (x: => Int, y: => Int)Int scala> test2(3+4,8) res1: Int = 14 //Comparison of execution process: test1 --> test1(3+4,8) --> test1(7,8) --> 7+7 --> 14 test2 --> test2(3+4,8) --> (3+4)+(3+4) --> 7+7 --> 14 //Notice here that the argument is always 3 + 4, not 7, until the argument is used
Here is a more obvious example:
//x is call by value, y is call by name def bar(x:Int,y: => Int) : Int = 1 Define a loop function def loop() : Int = loop Call bar function: 1,bar(1,loop) 2,bar(loop,1) Which way will produce a life and death cycle? The second way Analysis: 1. Every time y is used in a function, it will be evaluated. The bar function does not use y, so it will not call loop. 2. x call by value, to evaluate the function parameters (whether used or not), and only once, so it will generate a life and death cycle.2.5.2 function parameter type
1. Default parametersWhen you do not assign a value to a parameter, the default value is used. scala> def fun1(name:String="Tom") : String = "Hello " + name fun1: (name: String)String scala> fun1("Andy") res0: String = Hello Andy scala> fun1() res1: String = Hello Tom2. Proxy parameters
The override parameter determines which parameter to assign. scala> def fun2(str:String="Good Morning ", name:String="Tom ", age:Int=20)=str + name + " and the age is " + age fun2: (str: String, name: String, age: Int)String scala> fun2() res2: String = Good Morning Tom and the age is 20 //Which default parameter is assigned here scala> fun2(name="Mary ") res3: String = Good Morning Mary and the age is 203. Variable parameters
Be similar to java The variable parameter in, that is, the number of parameters is not fixed, is to add a parameter after the common parameter * //Example: //Find the sum of multiple numbers: def sum(args:Int*) = { var result = 0 for(s <- args) result += s result } //This is the variable parameter scala> def sum(args:Int*) = { | var result = 0 | for(s <- args) result += s | result} sum: (args: Int*)Int scala> sum(1,2,4) res4: Int = 7 scala> sum(1,2,4,3,2,5,3) res5: Int = 20
2.6 lazy value
Definition: if a constant (defined by val) is lazy, its initialization will be delayed until it is used for the first time. For example:
scala> val x : Int = 10 x: Int = 10 scala> val y:Int = x+1 y: Int = 11 y No lazy,Trigger calculation immediately after definition scala> lazy val z : Int = x+1 z: Int = <lazy> z yes lazy,Initialization will be delayed and calculation will not start at definition time. scala> z res6: Int = 11 //When we use z for the first time, we trigger the calculation.
Extension:
The core of spark is RDD (data set). Spark provides many methods to operate RDD and operators. There are two types of operators: 1. Transformation: delay loading, no calculation will be triggered 2. Action: calculation will be triggeredLet's take another example:
(1)Read an existing file scala> lazy val words = scala.io.Source.fromFile("H:\\tmp_files\\student.txt").mkString words: String = <lazy> scala> words res7: String = 1 Tom 12 2 Mary 13 3 Lily 15 (2)Read a file that does not exist scala> val words = scala.io.Source.fromFile("H:\\tmp_files\\studen1231312312t.txt").mkString java.io.FileNotFoundException: H:\tmp_files\studen1231312312t.txt (The system cannot find the specified file.) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at scala.io.Source$.fromFile(Source.scala:91) at scala.io.Source$.fromFile(Source.scala:76) at scala.io.Source$.fromFile(Source.scala:54) ... 32 elided //Exceptions will occur scala> lazy val words = scala.io.Source.fromFile("H:\\tmp_files\\studen1231312312312t.txt").mkString words: String = <lazy> //If it is a lazy value, no exception will be generated, because it is not executed at the time of definition, so no exception will be generated
2.7 exception
Similar to java, try catch finally is used to catch and handle exceptions
try {} catch { case ex: exception_type1 => { Exception handling code } case ex: exception_type2 => { Exception handling code } case _:Exception => { This is to include all exception s. If the above ones don't match, here they are } } finally { xxxx }2.8 array
Array type:
Array[T](N) fixed length array, array length needs to be specified ArrayBuffer variable length array, need to import package import scala.collection.mutable_Array operation:
scala> val a = new Array[Int](10) a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) //Initialize assignment, default 0 scala> val b = new Array[String](15) b: Array[String] = Array(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null) scala> val c = Array("Tom","Mary","Andy") c: Array[String] = Array(Tom, Mary, Andy) scala> val c = Array("Tom","Mary",1) c: Array[Any] = Array(Tom, Mary, 1) //The Array type is not declared. It is assigned directly. The Array is of Any type, that is, Any type can be used scala> val c:Array[String]=Array("Tom","Andy",1) <console>:11: error: type mismatch; found : Int(1) required: String val c:Array[String]=Array("Tom","Andy",1) //Array elements must be all strings when Array[String] is declared ^ scala> val c:Array[String]=Array("Tom","Andy") c: Array[String] = Array(Tom, Andy)
ArrayBuffer operation:
scala> import scala.collection.mutable._ import scala.collection.mutable._ mutable Representative variable scala> val d = ArrayBuffer[Int]() d: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer() //Add elements to an array scala> d += 1 res8: d.type = ArrayBuffer(1) //Access the element of the specified subscript of the array: d(index) //Delete the specified element (not the element with the specified subscript): scala> y-=3 res6: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1)
Array common operations:
1,Traversal array: scala> var a = Array("Tom","Andy","Mary") a: Array[String] = Array(Tom, Andy, Mary) scala> for(s<-a) println(s) Tom Andy Mary scala> a.foreach(println) Tom Andy Mary 2,Find the maximum and minimum scala> val myarray = Array(1,2,7,8,10,3,6) myarray: Array[Int] = Array(1, 2, 7, 8, 10, 3, 6) scala> myarray.max res16: Int = 10 scala> myarray.min res17: Int = 1 3,sort //Indicates sorting with a comparison function scala> myarray.sortWith(_>_) res18: Array[Int] = Array(10, 8, 7, 6, 3, 2, 1) scala> myarray.sortWith(_<_) res19: Array[Int] = Array(1, 2, 3, 6, 7, 8, 10) //Explanation: myArray. Sortwith (> //Complete: myArray. Sortwith ((a, b) = > ) (a,b)=> It's an anonymous function without a name. Two parameters are passed in a b,The return value is bool sortWith(_>_) Is a higher-order function, that is, the parameter is a function
Multidimensional array:
and Java Similarly, it is realized through the array of arrays //Define a fixed length 2D array scala> val matrix = Array.ofDim[Int](3,4) matrix: Array[Array[Int]] = Array( Array(0, 0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0) ) scala> matrix(1)(2)=10 scala> matrix res21: Array[Array[Int]] = Array( Array(0, 0, 0, 0), Array(0, 0, 10, 0), Array(0, 0, 0, 0)) //Define a two-dimensional array, where each element is a one-dimensional array, and its length is not fixed scala> var triangle = new Array[Array[Int]](10) triangle: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null) scala> for(i <- 0 until triangle.length) | triangle(i)=new Array[Int](i+1) scala> triangle res23: Array[Array[Int]] = Array( Array(0), Array(0, 0), Array(0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
2.9 Map
Map[K,V] () the generic type can be determined automatically according to the incoming value. If the creation is empty, KV is of nothing type scala.collection.mutable.Map is a variable Map, and the added KV can be changed scala.collection.immutable.Map is immutable Map Example: //Initialize assignment mode 1 scala> val scores = Map("Tom" -> 80, "Mary"->77,"Mike"->82) scores: scala.collection.mutable.Map[String,Int] = Map(Mike -> 82, Tom -> 80, Mary -> 77) //Initialize assignment mode 2 scala> val chineses = Map(("Tom",80),("Mary",60),("Lily",50)) chineses: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Lily -> 50, Mary -> 60)Mapped actions:
1,Get value in map scala> chineses("Tom") res25: Int = 80 scala> chineses("To123123m") java.util.NoSuchElementException: key not found: To123123m at scala.collection.MapLike$class.default(MapLike.scala:228) at scala.collection.AbstractMap.default(Map.scala:59) at scala.collection.mutable.HashMap.apply(HashMap.scala:65) ... 32 elided //Solution: first determine whether the key exists if(chineses.contains("To123123m")){ chineses("To123123m") } else { 1 } scala> if(chineses.contains("To123123m")){ | chineses("To123123m") | } else { | 1} res27: Int = 1 //Gets the value of the specified key, and returns - 1 if the key does not exist, similar to returning the default value scala> chineses.getOrElse("To123123m",-1) res28: Int = -1 //get method if the corresponding key does not exist, value returns none scala> chineses.get("dlfsjldkfjlsk") res29: Option[Int] = None //No error will be reported when using get method scala> chineses.get("Tom") res30: Option[Int] = Some(80) Option None Some The three types will be explained at the same time later. ========================================================== 2,Update values in map scala> chineses res31: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Lily -> 50, Mary -> 60) scala> chineses("Tom") res32: Int = 80 scala> chineses("Tom")=100 scala> chineses res34: scala.collection.mutable.Map[String,Int] = Map(Tom -> 100, Lily -> 50, Mary -> 60) ========================================================== 3,Iteration of mapping //You can use for foreach scala> chineses res35: scala.collection.mutable.Map[String,Int] = Map(Tom -> 100, Lily -> 50, Mary -> 60) scala> for(s <- chineses) println(s) (Tom,100) (Lily,50) (Mary,60) scala> chineses.foreach(println) (Tom,100) (Lily,50) (Mary,60) foreach In essence, it is a higher-order function. ========================================================== 4,Add value to map scala> a+="tom"->"king" Ahead is K,Behind is V
2.10 Tuple
Tuples are immutable types and cannot be added or modified. Tuple in Scala: a collection of different types of values
Tuple Statement: scala> val t1 = Tuple(1,0.3,"Hello") <console>:14: error: not found: value Tuple val t1 = Tuple(1,0.3,"Hello") ^ scala> val t1 = Tuple3(1,0.3,"Hello") t1: (Int, Double, String) = (1,0.3,Hello) Tuple3 representative Tuple There are three elements in //You can use the following method to define the number of meta ancestors of any element scala> val t1 = (1,0.3,"Hello") t1: (Int, Double, String) = (1,0.3,Hello) scala> val t1 = (1,0.3,"Hello",1,12,5,"all") t1: (Int, Double, String, Int, Int, Int, String) = (1,0.3,Hello,1,12,5,all) //Access element: note this special symbol scala> t1._1 Access the first element in the ancestor res38: Int = 1 scala> t1._3 Access the third element in the ancestor res39: String = Hello
Traverse tuple:
Note: the foreach function is not provided in Tuple, we need to use the productIterator The traversal is divided into two steps: 1. Use productIterator to generate iterator 2, traversal scala> t1.productIterator.foreach(println) 1cala> 0.3 Hello 1 12 5 all2.11 document operation
//To read a file, source itself is an iterative object stored by characters, which is single character by default val source = scala.io.Source.fromFile(fileName, character set) //Read the entire contents of the file into a string source.mkString //Read by line, one line at a time source.getLines() //Read by single character for(c<-source) { println(c) } //Read data content from URL val source2 = scala.io.Source.fromFile(URL, UTF-8) //When reading binary files, scala does not implement its own classes, so it calls java classes directly val file=new File(filename) val in=new FileInputStream(file) val buffer=new Array[Byte](file,.length().toInt) in.read(buffer) //write file val out=new PrintWriter(filename) out.println(xxxxx) Write contents
Use the properties class to resolve the properties configuration file under the resources directory:
You can define a xx.properties configuration file and use the load method to read it. The basic format of the configuration file is the format of key=value, and the module will parse it into kv format. Example: object Dataloader { def main(args: Array[String]): Unit = { val properties = new Properties() //Note that the compiled file path is used here, so this is the input stream to get the compiled path of the file in the resource directory val propertiesStream = Dataloader.getClass.getClassLoader.getResourceAsStream("dataloader.properties") properties.load(propertiesStream) println(properties.getProperty("spark.local.cores")) } } 3. The object-oriented characteristics of scala3.1 definition of class
The definition of a class in scala is similar to that in java. The class keyword is also used to define a class, but there are no public and other modifiers in front of the class keyword. Example:
class Student1 { //Defining student attributes private var stuId : Int = 0 private var stuName : String = "Tom" private var age : Int = 20 //Define member method (function) get set def getStuName() : String = stuName def setStuName(newName :String) = this.stuName = newName def getStuAge() : Int = age def setStuAge(newAge : Int) = this.age = newAge }
In fact, scala will automatically generate corresponding get and set methods for attributes, but the following principles should be noted:
1. By default, if the attribute is not decorated with any modifiers, it is private by default, but the automatically generated get and set methods are public 2. If the explicit declaration attribute is private (using the private keyword explicitly), such as private var a = 10, then the generated get and set methods are private. Can only be used in companion objects, or in this class 3. If private [this] var a = 10 is used to define the attribute, it means that the attribute can not be accessed externally (including associated classes), and the set and get methods will not be generated 4. If you want scala to generate a get method instead of a set method, you can define it as a constant, because the value of a constant cannot be changed ==================Essence=================== The automatically generated set and get method names are consistent with the property names, such as: var student = new Student1() student.stuId actually calls the get method of this property directly here, but the name of the method is the same student.age=10 in this case, the set method of the property is actually called3.2 internal
scala's inner class is not as complex as java's, that is, it is simple to define a class directly in the outer class. Example:
class Student2 { //Defining student attributes private var stuName : String = "Tom" private var stuAge : Int = 20 //Define an array to save students' course scores private var courseList = new ArrayBuffer[Course]() //Define a function to add a student's course grade def addNewCourse(cname:String,grade:Int) = { //Create course grade information var c = new Course(cname,grade) //Add to student's object courseList += c } //Defining the main constructor of the course class is written after the class class Course(var courseName:String,var grade:Int){ //Defining properties //Defining functions } } You can get the objects of the inner class through the methods of the outer class. Or create an inner class object by val test = new InnerClassTest() only when the external class object is defined with val var testIn = new test.myClass("king") Note that the following way definitions are error reporting var test = new InnerClassTest(), here is var var testIn = new test.myClass("king") Personal understanding: In scala, the inner class belongs to the object of the outer class, not the outer class (this is official) So the inner class object also follows the outer class object. If the external class object is defined by var, it means that it is mutable If it changes, how can internal class objects get themselves through the reference of external class objects?Class 3.3 constructors
3.3.1 main constructor
The main constructor is defined at the same time after the definition class, such as:
class Student3(var stuName : String , var age:Int) //Inside the brackets are the main constructors, only some attributes. //It should be noted that the preceding var or val of the attribute variable defined in brackets must not be lost. If it is lost, the parameter can only be used as an immutable parameter within the class, not as a field of the class, neither can it be accessed externally. It will result in the following consequences, for example: //First of all, there are two classes, the main constructor and the difference between VaR and no var class a(var name:String) class b(name:String) object IODemo { def main(args: Array[String]): Unit = { //Here you can create objects normally val king = new a("king") val wang = new b("wang") //There's a problem here king.name This is OK wang.name This will not be accessible name This property, because it doesn't exist at all, just as class A common variable in } } //Another point is that if there is any code in the class that is not included in any methods in the class, in fact, when creating class objects, these codes will be executed, so they are actually part of the main constructor. Such as: class a(var name:String){ println("hahha") //This statement is executed when an object is created def test()={ println("test") } }
3.3.2 auxiliary constructor
A class can have multiple auxiliary constructors through keywords this To achieve,Such as: class Student3(var stuName : String , var age:Int) { //attribute private var gender:Int = 1 //Define an auxiliary constructor. There can be multiple auxiliary constructors //Auxiliary constructor is a function, but its name is this def this (age : Int){ this("Mike",age) // new Student3("Mike",age) println("This is an auxiliary constructor") } def this (){ this(10)// new Student3("Mike",10) println("This is auxiliary constructor 2") } }
3.4 object object (companion object)
Object object is a special object in scala. It has several characteristics
1. The content in the Object is static. So the properties and methods defined in it are static and can be called directly through the class name without creating objects 2. In scala, there is no static keyword, and all static are defined in the object. For example, the main function 3. If the name of the class is the same as the name of the object, the object is called the companion object of the class. Companion objects. 4. The main function needs to be written in the object, but not necessarily in the associated object 5. In essence, an object is similar to a singleton object. It is static in itself, and does not need to instantiate an object to call the methods and properties defined in it. So from this point of view, it can be regarded as a remedy for the lack of static attributes in scalaAn example of using the singleton object property of an object object object:
1,Generate credit card number object CreditCard { //Define a variable to save credit card number private [this] var creditCardNumber : Long = 0 //Define functions to generate card numbers def generateCCNumber():Long = { creditCardNumber += 1 creditCardNumber } //Test program def main(args: Array[String]): Unit = { //Create a new card number println(CreditCard.generateCCNumber()) println(CreditCard.generateCCNumber()) println(CreditCard.generateCCNumber()) println(CreditCard.generateCCNumber()) println(CreditCard.generateCCNumber()) println(CreditCard.generateCCNumber()) println(CreditCard.generateCCNumber()) } } 2,Extended use, App This class //Define the object class, inherit the App class, and omit the main function. All the codes in the default object are in the main function. Such as: object AppTest extends App { println("test") This will be done directly }
3.5 apply method
At this point, the previous estimation has some questions. Why do you sometimes use the new keyword when creating objects, and sometimes you don't? That's the way to apply. Such as:
var t1 = Tuple3(1,0.1,"Hello")
As you can see, a tuple object is created, but the new keyword is not used. In fact, when the new keyword is omitted, the apply method in the companion object of this class is called. Generally, the apply method will return the object of the created class. Pay attention to the following points:
1. Use the apply method to make the program more concise. 2. The apply method must be written in the companion object. Because the direct call to the apply method needs to be static, it can only be written in the object accompanying object 3. This is similar to creating objects by class name. method, In the way of java, that is to say, object is a static class, and the class name can be used directly Call the static method inside 4. Inside the apply method, new is also used to create objects of corresponding classesExample:
//Define a primitive class class Student4 (var stuName : String) //Define the companion object of the above class object Student4{ //Define the apply method def apply(name : String) = { println("call apply Method") //Returns the object of the original class new Student4(name) } //Test program def main(args: Array[String]): Unit = { //Creating student objects through the main constructor var s1 = new Student4("Tom") println(s1.stuName) //Create the student object through the apply method without writing the new keyword var s2 = Student4("Mary") println(s2.stuName) } }
3.6 inheritance
3.6.1 general inheritance
In scala, the extensions keyword is also used to inherit the parent class, and only single inheritance is allowed, such as:
//Define parent class class Person(val name: String,val age:Int){ //Defining functions def sayHello() : String = "Hello " + name + " and the age is " + age } //Defining subclasses /** *class Emplyee(val name:String,val age:Int,val salary:Int) extends Person(name,age) *Error in the above writing *If you want to use the properties of a subclass, override the properties of the parent. No need to override * *Override is to use the value in the subclass to override the value in the parent class * */ class Emplyee(override val name:String,override val age:Int,val salary:Int) extends Person(name,age){ //Override method of parent class override def sayHello(): String = "sayHello in subclass" } When overriding the methods or properties of the parent class, you need to add the override keyword at the top3.6.2 anonymous subclass inheritance
object Demo1 { def main(args: Array[String]): Unit = { //Create Person object var p1 = new Person("Tom",20) println(p1.name+"\t"+p1.age) println(p1.sayHello()) //Create Employee object var p2 : Person = new Emplyee("Mike",25,1000) println(p2.sayHello()) //Inheritance is realized by hiding subclasses: subclasses without names are called anonymous subclasses var p3 : Person = new Person("Mary",25){ override def sayHello(): String = "In the anonymous subclass sayHello" } println(p3.sayHello()) } }
3.6.3 abstract classes and fields
Abstract class is actually a class defined by the abstract keyword, such as:
abstract class Teacher { var i:Int var name:String="king" def test = { } def sayHello def talk:Int } Among them, there are the following points 1. In an abstract class, fields that are not initialized are called abstract fields or properties. If they are initialized, they are not abstract fields. Similarly, a method without implementation is called an abstract method. 2. Abstract classes can only be used for inheritance, and cannot instantiate objects 3. In the non Abstract subclass, it inherits the abstract parent class and must initialize the abstract field and implement the abstract method. When initializing abstract fields, you can also initialize them in the main constructor of a subclass or in the class implementation. However, in the main constructor, initialization is not needed immediately, and parameters can be passed in for initialization when the object is instantiated. In class implementation, it must be initialized immediately 4. In the abstract class, for the abstract attribute, only the corresponding get method will be generated automatically, not the set method 5. The extension keyword is also used to inherit the abstract parent class.3.7 trait
In scala, only single inheritance is generally supported, but sometimes multiple inheritance is needed, so a trait appears, which can make subclasses inherit more. The definition of trait is basically similar to that of abstract class. Such as:
//Defining parent class trait Human{ //Defining abstract properties val id : Int val name : String } //Define a trait that represents an action trait Action{ //Define an abstract function def getActionName():String } //To define a subclass to inherit from two parents class Student5(val id:Int,val name:String) extends Human with Action{ override def getActionName(): String = "Action is running" }
It can also be seen from the above that when inheriting a trait, two keywords of extends + with are used. When there is more than one parent class, the with keyword must be used to inherit and the class must be trait. The class after extends can be a trait or other class. Multiple inheritance is as follows:
class Father extends class1 with trait1 with trait2 with . . . . . . { }
3.8 packages and package objects
The use of scala packages is similar to java, and in Scala, the import statement can be anywhere. In general, under the packages of java and Scala, there can only be classes, objects, characteristics, and functions and variables cannot be defined directly. Scala's package object can solve this problem. Package objects in scala can include: constants, variables, methods, classes, objects, trait s. Such as:
package object MyPackage { def test = { } var x:Int = 0 class a {} }
Then you can directly call the methods and variables in the package object name
IV. collections in scalaIn Scala, collections are generally divided into variable collections and immutable collections, respectively, under the scala.collection.mutable and scala.collection.immutable packages. Adding elements, changing the value of an element and deleting elements are not allowed in immutable collection.
4.1 List
List[T] () immutable list LinkedList[T] () variable listList[T] related operations:
scala> val nameList = List("Tom","Andy") nameList: List[String] = List(Tom, Andy) scala> val intList = List(1,2,3) intList: List[Int] = List(1, 2, 3) Null list scala> val nullList : List[Nothing] = List() nullList: List[Nothing] = List() Two dimensional list scala> val dim:List[List[Int]] = List(List(1,2,3),List(10,20)) dim: List[List[Int]] = List(List(1, 2, 3), List(10, 20)) Returns the first element nameList.head Returns the list of last elements removed nameList.tail Access the element of the specified index nameList(index)LinkedList[T] related operations:
Define variable list scala> val myList = scala.collection.mutable.LinkedList(1,2,3,4,5) warning: there was one deprecation warning; re-run with -deprecation for details myList: scala.collection.mutable.LinkedList[Int] = LinkedList(1, 2, 3, 4, 5) //Traverse modification list var cur = myList point nameList Memory address reference for while(cur != Nil){ cur.elem = cur.elem*2 Iterate over each element and change each element *2 cur = cur.next } col: + ele //Add element's to the tail of the collection (seq) ele +: col //Add elements to the header of the collection (seq) col + (ele,ele) //Add other sets to the set / map tail col -(ele,ele) //Remove a subset from a set (set / map / ArrayBuffer) col1 ++ col2 //Add other sets to the end of the set (Iterator) col2 ++: col1 //Add another collection to the header of the collection (Iterator) ele::list //Add element to list header (list) list2::list1 //Add another list2 to list1 //Head of (list) list1:::list2 //Add another list2 to the tail of list1 (list)
4.2 sequence
The sequence is divided into Vector and Range, both of which are immutable
Vector operation:
Vector Is a sequence with subscripts, which can be accessed by subscripts (index marks) Vector element scala> var v = Vector(1,2,3,4,5,6) v: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4, 5, 6)
Range operation:
Range: Is a sequence of integers //The first way: scala> Range(0,5) res48: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4) //Explanation: starting from 0, excluding 5 //The second way of writing: scala> print(0 until 5) Range(0, 1, 2, 3, 4) //The third way: front and back closed interval scala> print(0 to 5) Range(0, 1, 2, 3, 4, 5) //Two ranges can be added scala> ('0' to '9') ++ ('A' to 'Z') res51: scala.collection.immutable.IndexedSeq[Char] = Vector(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z) Range convert to list scala> 1 to 5 toList warning: there was one feature warning; re-run with -feature for details res52: List[Int] = List(1, 2, 3, 4, 5)
4.3 set
The default is HashSet, which is similar to java, immutable, and related operations
Create a set scala> var s1 = Set(1,2,10,8) s1: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8) //Note: belonging to immutable scala> s1 + 10 res53: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8) scala> s1 + 7 res54: scala.collection.immutable.Set[Int] = Set(10, 1, 2, 7, 8) //Return to a new Set scala> s1 res55: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8) s1 Not changed by itself //Create a sortable Set scala> var s2 = scala.collection.mutable.SortedSet(1,2,3,10,8) s2: scala.collection.mutable.SortedSet[Int] = TreeSet(1, 2, 3, 8, 10) //Determine whether the element exists: scala> s1.contains(1) res56: Boolean = true //Determine whether a set is a subset of another set scala> var s2 = Set(1,2,10,8,7,0) s2: scala.collection.immutable.Set[Int] = Set(0, 10, 1, 2, 7, 8) scala> s1 res57: scala.collection.immutable.Set[Int] = Set(1, 2, 10, 8) scala> s1 subsetOf(s2) res58: Boolean = true //Operation of set: union Union union, intersect intersection, diff difference set scala> var set1 = Set(1,2,3,4,5,6) set1: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4) scala> var set2 = Set(5,6,7,8,9,10) set2: scala.collection.immutable.Set[Int] = Set(5, 10, 6, 9, 7, 8) scala> set1 union set2 res59: scala.collection.immutable.Set[Int] = Set(5, 10, 1, 6, 9, 2, 7, 3, 8, 4) scala> set1 intersect set2 res60: scala.collection.immutable.Set[Int] = Set(5, 6) scala> set1 diff set2 res61: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4) scala> set2 diff set1 res62: scala.collection.immutable.Set[Int] = Set(10, 9, 7, 8)V. functions in scala
The definition of ordinary functions mentioned above is as follows:
Keyword def function name (parameter): return value = function implementationIn addition to ordinary functions, there are other functions.
5.1 anonymous functions
A function without a name is defined as:
(parameter list) = > Note, yes = > no=Generally speaking, anonymous function is used to define a function temporarily. It is used only once, often in combination with higher-order functions. Example:
Call anonymous function Define an array, multiply each element in the array by three Pass each element in Array(1, 2, 3) to anonymous function (X: int) = > x * 3 scala> Array(1,2,3).map((x:Int) => x*3) res1: Array[Int] = Array(3, 6, 9) Pass (X: int) = > x * 3 as the function parameter of map to the higher-order function (1) what does this mean? All functions are anonymous. When defining anonymous functions, parameter lists can be omitted and function bodies can be used directly, such as: (I: int) = > I * 2 can be omitted as "* 2", where "means parameter and output type is automatically detectedOne thing to note:
In the input parameters of anonymous functions, it is not mandatory to specify the type of parameters, and it can be automatically detected, such as:
5.2 higher order functions
A higher-order function is one that uses another function as a parameter in the parameter list. Usage:
Define a higher-order function: def function name (passed in function name, assumed to be f: (input parameter type) = > (output parameter type), parameter 2,.... )= processing logic, in which the incoming function will be called Example: object IODemo { def main(args: Array[String]): Unit = { //Call a higher-order function and pass in the function as an argument highFun(innerFun,2) } //High order function, there are two parameters, one is function f, the specified input and output parameter types are Int, the other is x:Int def highFun(f:(Int)=>(Int),x:Int) = { f(x) } //This is the function that is then passed into the higher-order function def innerFun(x:Int) = { x+2 } } In addition to using existing functions as parameters of higher-order functions, anonymous functions can also be used, such as: Highfun ((X: int) = > x * 3, 3), (X: int) = > x * 3 is an anonymous function5.3 common higher-order functions in Scala
5.3.1 map function
It is equivalent to a loop that operates on each element in a collection (according to the logic in the receive function) and returns a new collection of processed data. Example:
scala> var numbers = List(1,2,3,4,5,6,7,8,9,10) numbers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) scala> numbers.map((i:Int)=>i*2) res8: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) In (i: int) = > i * 2, i is a cyclic variable, the entire function The map function does not change the numbers value scala> numbers res10: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) Anonymous functions can be abbreviated as; _Equivalent to loop variable i _*2 has the same function as (I: int) = > I * 2 _+_And (I: int, j: int) = > I + J Note: if a map type is passed to the map, and the key is not processed to the function in the map, only value is processed, then the new set returned after the map processing only contains value5.3.2 foreach function
Similar to map, the only difference is that it has no return value
scala> numbers res11: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) scala> numbers.foreach(_*2) scala> numbers res13: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) scala> numbers.foreach(println(_)) 1 2 3 4 5 6 7 8 9 10 scala> numbers.map(_*2).foreach(println) 2 4 6 8 10 12 14 16 18 20
5.3.3 filter
Filter. Select the data that meets the requirements. If true is returned, the data will be retained. If false is returned, the data will be discarded. The final returned new collection contains elements that meet the criteria. Example:
For example: query the number divisible by 2 scala> numbers res15: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) scala> numbers.filter((i:Int)=>i%2==0) res16: List[Int] = List(2, 4, 6, 8, 10) Note: (I: int) = > I% 2 = = 0 if true, return5.3.4 zip
Merge two sets, for example:
scala> List(1,2,3).zip(List(4,5,6)) res18: List[(Int, Int)] = List((1,4), (2,5), (3,6)) scala> List(1,2,3).zip(List(4,5)) res19: List[(Int, Int)] = List((1,4), (2,5)) //As you can see, it is the combination of two elements in two sets into a primitive ancestor, and it is based on the list of the least elements scala> List(3).zip(List(4,5)) res20: List[(Int, Int)] = List((3,4))
5.3.5 partition
Partition according to the result of an assertion (that is, a condition that can be implemented through an anonymous function). The type returned by the function must be of type boolean. Finally, the one that returns true is one partition, and the one that returns false is another partition. Such as:
Divide those that can be divided by 2 into one area and those that cannot be divided into another area scala> numbers res21: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) scala> numbers.partition((i:Int)=>i%2==0) res22: (List[Int], List[Int]) = (List(2, 4, 6, 8, 10),List(1, 3, 5, 7, 9))5.3.6 find
Find the first element that satisfies the condition (assertion)
For example: find the first number divisible by 3 scala> numbers.find(_%3==0) res23: Option[Int] = Some(3)5.3.7 flatten
Expand nested results
scala> List(List(2,4,6,8,10),List(1,3,5,7,9)).flatten res24: List[Int] = List(2, 4, 6, 8, 10, 1, 3, 5, 7, 9) Merge into a collection5.3.8 faltmap
Equivalent to map+flatten
scala> var myList = List(List(2,4,6,8,10),List(1,3,5,7,9)) myList: List[List[Int]] = List(List(2, 4, 6, 8, 10), List(1, 3, 5, 7, 9)) scala> myList.flatMap(x=>x.map(_*2)) res25: List[Int] = List(4, 8, 12, 16, 20, 2, 6, 10, 14, 18) Execution process: 1. Cycle List(2,4,6,8,10) and List(1,3,5,7,9) and call x = > X. map (x2) where X represents a list, and the xrepresents the elements in the list List(4, 8, 12, 16, 20) and List(2, 6, 10, 14, 18) 2. Merge into a List List(4, 8, 12, 16, 20, 2, 6, 10, 14, 18)5.4 closure
Closures are the nesting of functions. In one function, it contains the definition of another function, which can access the variables of the external function in the internal function. Such as:
Def mulby (factor: double) = (X: double) = > x * factor in which the external function is called Outside inside5.5 Coriolis
The Coriolis function is to transform a function with multiple parameters into a function chain, and each node is a single parameter function
def add(x:Int,y:Int)=x+y def add(x:Int)(y:Int)=x+y The above two functions are equivalent when they are defined Explain: Normal function: def add(x:Int,y:Int)=x+y Collierization function: the way to use the function closure above def add(x:Int)=(y:Int)=>x+y Abbreviation: def add(x:Int)(y:Int)=x+y scala> def add(x:Int)(y:Int)=x+y add: (x: Int)(y: Int)Int scala> add(1)(2) res28: Int = 35.6 answering questions
Sometimes when a method is called, there is no need to add parentheses after the method name. Sometimes? Why?
It mainly depends on whether there are parentheses after defining functions. Of course, when there are no parameters in a function, there must be parentheses if there are parameters. When a function is parameterless and is defined without parentheses, it must be called without parentheses When a function is a nonparametric function and the definition is bracketed, the parentheses are optional when callingThe same is true when defining a class
Vi. high order characteristics6.1 special types in Scala
* Any Indicates that any type is equivalent to java Medium Object * Unit No value, equivalent to void * Nothing Nothing Type in Scala The lowest level of the class hierarchy of; it is a subtype of any other type * Null Is a subclass of all application types with a value of null * * Special types: * Option : Scala Option(Option) type is used to indicate that a value is optional (with or without value) * Some : If the value exists, Option Namely Some * None : If the value does not exist, Option Namely None * * scala> var myMap = Map("Andy"->90) myMap: scala.collection.immutable.Map[String,Int] = Map(Andy -> 90) scala> myMap.get("Andy") res0: Option[Int] = Some(90) scala> myMap.get("ykjdfhsdajfkajshd") res1: Option[Int] = None * * Nil Type: is empty List * * Four N Conclusion: None Nothing Null Nil * None : If map The value in does not exist, Option Namely None * Nothing : If the method throws an exception, the return value type is Nothing,Nothing Is a subtype of any other type * Null : It can be assigned to all reference types, not to value types. * Nil : Empty List
6.2 pattern matching
Similar to switch/case in java, usage:
xx match { case xx1=>. . . . Match 1 case xx2=>. . . . Match 2 case _ => ...... Here is the meaning of the default value, equivalent to default }
Example:
object Demo1 { def main(args: Array[String]): Unit = { //1. Equivalent to switch case var chi = '-' var sign = 0 //Identifier if chi is' - ', then sign is assigned to - 1 chi match { case '+' => sign = 1 case '-' => sign = -1 case _ => sign=0 // _Indicates other values } println(sign) /** * 2,Scala Guard of: matches all values of a certain type case if * * For example, match all numbers. If ch2 is a number, then digit is assigned ch2 */ var ch2 = '6' var digit : Int = -1 ch2 match { case '+' => println("This is a plus sign") case '-' => println("This is a minus sign") case _ if Character.isDigit(ch2) => digit = Character.digit(ch2,10)// 10 for decimal case _ => println("Other") } println(digit) /** * 3,Using variables in pattern matching */ var mystr = "Hello World" //Take a character and assign it to the variable of pattern matching mystr(7) match { case '+' => println("This is a plus sign") case '-' => println("This is a minus sign") case ch => println(ch)//The variable ch is used in the case statement to represent the characters passed in } /** * 4,Matching type: equivalent to instanceof in java */ var v4 : Any = 100 // The final v4 is an integer v4 match { case x : Int => println("This is an integer") case s : String => println("This is a string") case _ => println("Other types") } /** * 5,Match arrays and lists */ var myArray = Array(1,2,3) myArray match { case Array(0) => println("There is only one 0 in the array") case Array(x,y) => println("Array contains two elements") case Array(x,y,z) => println("Array contains 3 elements") case Array(x,_*) => println("This is an array with multiple elements") } var myList = List(1,2,3,4,5,6) myList match { case List(0) => println("There is only one 0 in the list") case List(x,y) => println("The list contains two elements,And: " + (x+y)) case List(x,y,z) => println("List contains 3 elements,And: "+ (x+y+z)) case List(x,_*) => println("This is a list with multiple elements,And: " + myList.sum) } } }
6.3 sample class case
The sample class has one more feature than the ordinary class. You can use the case statement above as the matching type. Ordinary classes are not allowed. Other uses are the same as ordinary classes. Definition method:
case class a(x:int.....) {} Note that in the sample class, all fields will be declared as val automatically, so we can omit the val keyword when declaring fieldsIn fact, there is nothing to say. The usage is very simple. Commonly used as a storage class for some data
6.4 generic
The definition of generics in scala is similar to that in java. It is not repeated here, and it will be used directly.
6.4.1 generic classes
When defining a class, it has a generic type, such as:
class Father[T]{ xxxxx }
The way of definition is the same as in java. Many of scala have generics, such as:
Array[T] List[T] Map[K,V]
6.4.2 generic functions
When defining a function, define a generic type, such as:
def mkArray[T:ClassTag] ClassTag Explanation: indicated in scala The status information at run time, which represents the data type at call time
Example:
scala> import scala.reflect.ClassTag import scala.reflect.ClassTag //A generic array is defined, where elem: * represents all elements scala> def mkArray[T:ClassTag](elem:T*) = Array[T](elem:_*) mkArray: [T](elem: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]
6.5 implicit conversion
6.5.1 implicit conversion function
In general, scala automatically converts some types to specified types. As long as the user defines the relevant implicit conversion function, scala will automatically call according to the input and output parameter types of the implicit function. Example:
class Fruit(name:String){ def getFruitName() : String = name } class Monkey(f:Fruit){ //output def say() = println("Monkey like " + f.getFruitName()) } object ImplicitDemo { def main(args: Array[String]): Unit = { //Define a fruit object var f : Fruit = new Fruit("Banana") f.say() /** * Question: can f.say * Direct write will report an error, because there is no say function in Fruit * But Monkey has a say function * * If you can convert Fruit to Monkey, you can call say * * So we define implicit conversion functions * */ } //Defining implicit conversion functions implicit def fruit2Monkey(f:Fruit):Monkey = { new Monkey(f) } /** * Note: use implicit transformation with caution, which will lead to further poor readability of scala * * Implicit conversion function name: XXXXXXX */ }
6.5.2 implicit parameters
Implicit parameter is to add an implicit keyword before each parameter when defining a function. This parameter is an implicit parameter. Example:
Define a function with an implicit parameter scala> def testParam(implicit name:String) = println("The value is " + name) testParam: (implicit name: String)Unit Then define an implicit variable scala> implicit val name:String = "AAAAAA" name: String = AAAAAA Pass in parameter call method, which can run scala> testParam("dfsfdsdf") The value is dfsfdsdf When no parameter is passed, the defined implicit variable is automatically found, that is, the previous name. Currently, the implicit variable is not called by name scala> testParam The value is AAAAAA When there are multiple implicit variables, if there are multiple of the same type, an error will be reported. If it's a different type, you can scala> implicit val name2:String = "AAAAAACCCCCCCCCCCCCC" name2: String = AAAAAACCCCCCCCCCCCCC scala> testParam <console>:18: error: ambiguous implicit values: both value name of type => String and value name2 of type => String match expected type String testParam Note: when defining implicit parameters, there can only be one implicit parameter. Sometimes, for the convenience of viewing, implicit parameters and common parameters are defined separately, such as: def test1(c:Int)(implicit a:Int): Unit = {} Note that normal parameters must be in parentheses before, not afterAnother special example is the combination of implicit parameters and implicit conversion functions:
Define an implicit parameter to implement the following requirements: find the smaller value of the two values 100 23 ----> 23 "Hello" "ABC"--->ABC def smaller[T](a:T,b:T)(implicit order : T => Ordered[T]) = if(a<b) a else b scala> def smaller[T](a:T,b:T)(implicit order : T => Ordered[T]) = if(a<b) a else b smaller: [T](a: T, b: T)(implicit order: T => Ordered[T])T scala> smaller(100,23) res1: Int = 23 scala> smaller("Hello","ABC") res2: String = ABC //First of all, we are not sure whether the generic T can be compared, that is, whether there is a < method (don'T be surprised, < is a method name, not a symbol) in it. Because we need to determine whether there is, we define an implicit conversion function and parameter: implicit order : T => Ordered[T] //First, this is an anonymous implicit conversion function, which converts T to Order[T], and takes it as the value of the parameter order
6.5.3 implicit classes
Add implicit keyword before class name
Function: to enhance the function of a class by implicit class, the object of a class will be converted into an implicit class object, and then the method defined in the implicit class can be called. Example:
object ImplicitClassDemo { def main(args: Array[String]): Unit = { //Sum two numbers println("The sum of the two numbers is: " + 1.add(2)) // Replace 1 + 2 with 1.add(2) /** * 1.add(2) Error reported because 1 has no add method * * Define an implicit class to enhance the function of 1 * * Execution process: * First convert 1 to Calc(1) * Call Calc(1) add method again Is automatically called based on the type of parameter received in the implicit class */ implicit class Calc(x:Int){ def add(y:Int):Int = x + y } } }
6.6 upper and lower bounds of generics
Sometimes when you want to restrict the definition of generics to certain classes, you will use the concept of upper and lower bounds.
Example:
A small problem about the lower bound:
class Father class Son extends Father class Son1 extends Son class Son2 extends Son1 object Demo2 { def main(args: Array[String]): Unit = { var father : Father = new Son2 fun2(father) //fun2(new Son2) works normally. Why? //The main reason is that the object of the subclass can be assigned to the reference of the parent class, similar to automatic transformation. So when new son2 is used, it can actually be regarded as the object of the parent class, so it can work normally. It can be seen that the lower bound of generics is useless in the case of inheritance. In fact, it's the reason for polymorphism } def fun[T<:Son](x:T)={ println("123") } def fun2[T>:Son](x:T): Unit ={ println("456") } }
6.7 view definition
An extension of the upper and lower bounds that can receive types that can be implicitly converted in the past, in addition to the types specified by the upper and lower bounds. Such as:
Usage: def addTwoString[T<%String](x:T,y:T) = x + " " + y Meaning: 1. Can receive String and its subclasses 2. It can receive other types that can be converted to String. This is the point, which is the implicit transformationExample:
scala> def addTwoString[T<%String](x:T,y:T) = x + " **** " + y addTwoString: [T](x: T, y: T)(implicit evidence$1: T => String)String scala> addTwoString(1,2) <console>:14: error: No implicit view available from Int => String. addTwoString(1,2) //Error reporting solution: define implicit conversion function and convert int to String scala> implicit def int2String(n:Int):String=n.toString warning: there was one feature warning; re-run with -feature for details int2String: (n: Int)String scala> addTwoString(1,2) res13: String = 1 **** 2 //Analysis execution process: 1,call int2String Method Int convert to String(scala Call in the background, no need to display the call) 2,call addTwoString Methods, concatenating strings //Implicit conversion function, it can be called without display calling it.
6.8 covariance and inversion
Grafting the type of a generic variable into a generic class Concept: Covariant: the value of a generic variable can be of its own type or its subtype, Inverse: the value of a generic variable can be of its own type or its parent type Express: Covariant + class A[+T] means to graft the type of T generics into A Inverter -6.9 comparison of ordered and Ordering
These two classes are mainly used for comparison
Ordered is similar to java's comparable interface
Ordering is similar to java's comparator interface.
trait Ordered[A] extends scala.Any with java.lang.Comparable[A] { def compare(that : A) : scala.Int def <(that : A) : scala.Boolean = { /* compiled code */ } def >(that : A) : scala.Boolean = { /* compiled code */ } def <=(that : A) : scala.Boolean = { /* compiled code */ } def >=(that : A) : scala.Boolean = { /* compiled code */ } def compareTo(that : A) : scala.Int = { /* compiled code */ } } //This is actually a trait, which defines methods such as < and so on. No surprise, this is the method name. //The subclass can inherit the trait, override the methods in it, and the class can be used for comparison. trait Ordering[T] extends java.lang.Object with java.util.Comparator[T] with scala.math.PartialOrdering[T] with scala.Serializable { this : scala.math.Ordering[T] => def tryCompare(x : T, y : T) : scala.Some[scala.Int] = { /* compiled code */ } def compare(x : T, y : T) : scala.Int override def lteq(x : T, y : T) : scala.Boolean = { /* compiled code */ } override def gteq(x : T, y : T) : scala.Boolean = { /* compiled code */ } override def lt(x : T, y : T) : scala.Boolean = { /* compiled code */ } override def gt(x : T, y : T) : scala.Boolean = { /* compiled code */ } override def equiv(x : T, y : T) : scala.Boolean = { /* compiled code */ } def max(x : T, y : T) : T = { /* compiled code */ } def min(x : T, y : T) : T = { /* compiled code */ } override def reverse : scala.math.Ordering[T] = { /* compiled code */ } def on[U](f : scala.Function1[U, T]) : scala.math.Ordering[U] = { /* compiled code */ } class Ops(lhs : T) extends scala.AnyRef { def <(rhs : T) : scala.Boolean = { /* compiled code */ } def <=(rhs : T) : scala.Boolean = { /* compiled code */ } def >(rhs : T) : scala.Boolean = { /* compiled code */ } def >=(rhs : T) : scala.Boolean = { /* compiled code */ } def equiv(rhs : T) : scala.Boolean = { /* compiled code */ } def max(rhs : T) : T = { /* compiled code */ } def min(rhs : T) : T = { /* compiled code */ } } ordering There are many ways to use it