I. Basic Introduction to scala

[TOC]

I. overview of scala

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)

II. scala Foundation

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 this

2.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 variable

2.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 ${a}"
res1: String = my name is king
 Note: there is an s in front; it is equivalent to executing "my name is" + S1

2.1.3 Unit type

Equivalent to the void type in java, commonly used for the return value type of function methods

2.1.4 Nothing type

Generally, during execution, the type of exception generated is nothing

2.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 matching

2.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 it

2.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 them

Maybe 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 parameters

When 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 Tom

2. 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 20

3. 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 triggered

Let'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) = > {if (a > b) true else false})
(a,b)=>{if(a>b) true else false} 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
all

2.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 scala

3.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 called

3.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 scala

An 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 classes

Example:

//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 top

3.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 scala

In 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 list

List[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 implementation

In addition to ordinary functions, there are other functions.

5.1 anonymous functions

A function without a name is defined as:

(parameter list) = > {function implementation}
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 detected

One 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:

xxx.map(pair=>pair._2.toString)
The anonymous function in the map is legal and OK without specifying the input parameter type.

But ordinary functions must specify parameter types.

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 function

5.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 value

5.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, return

5.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 collection

5.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 inside

5.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 = 3

5.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 calling

The same is true when defining a class

Vi. high order characteristics

6.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 fields

In 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 after

Another 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:

(*) specifies the value range of generics
 For example: define a generic type: T
 Inheritance relationship of class a --- > b --- > C --- > d arrow points to subclass
 The value range of t can be specified d <: T <: B
 The value range of T can only be BCD

< is the representation of upper and lower bounds

(*) definition:
The upper bound S <: t specifies that the type of S must be a subclass or itself of T
 Lower bound U >: t specifies that the type of u must be the parent or itself of T

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 transformation

Example:

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

Tags: Big Data Scala Java Attribute Programming

Posted on Sun, 10 Nov 2019 08:11:37 -0500 by nayone