Scala essence is here, take it, interview is not afraid.

Posted by Jak on Mon, 11 Oct 2021 03:38:55 +0200

Make complaints about big data left and right hands plus technology Tucao group to get more information

preface

As an object-oriented functional programming language, Scala combines object-oriented programming with functional programming to make the code more concise, efficient and easy to understand. That's why Scala is popular.

As a JVM language, most components of the big data ecosystem are developed in Java language, and Scala can be seamlessly mixed with Java, so it can be well integrated into the big data ecosystem.

primary coverage

Some basic things are no longer listed, such as development environment, loops, exceptions, generics, etc. This article only introduces special places, focusing on concept understanding and usage.

  1. Variables and data types
  2. Functional programming
  • Higher order function
  • Anonymous function
  • closure
  • Function coritization
  1. object-oriented
  • Classes and objects
  • Companion Object
  • Idiosyncrasy
  1. pattern matching
  2. Implicit conversion

Variables and data types

Variable (var declares variable, val declares constant)

var modified variables can be changed

The variable modified by val cannot be changed

But is that true?

For the following definitions
class A(a: Int) {
  var value = a
}

class B(b: Int) {
  val value = new A(b)
}

Effect test
val x = new B(1)

x = new B(1) // Error, because x is decorated by val, the reference cannot be changed
x.value = new A(1) // Error, because x.value is modified by val, the reference cannot be changed

x.value.value = 1 // Correct. x.value.value is modified by var and can be re assigned

In fact, the object reference modified by var can be changed, while that modified by val cannot be changed, but the state of the object can be changed.

Variable and immutable understanding

We know that the List in scala is immutable, and the Map is variable and immutable. Look at the following example

var variable and List immutable combination
var list = List("Left","right")

list += "hand"
Understanding is

The object that var list points to is List("left", "right")

Later, modify the direction of the list, because it is a variable var modification, and the list can point to a new List("left", "right", "hand")

If it is the following (an error will be reported)

val list = List("Left","right")

list += "hand"
val var and Map variable and immutable
var map = Map(
      "Left" -> 1,
      "right" ->1,
    )
map+=("hand"->1)
val map=scala.collection.mutable.Map(
  "Left" -> 1,
  "right" ->1,
)

map+=("hand"->1)
understand

Immutable map when adding elements, the original map remains unchanged, and a new map is generated to save the original map + added elements.

When adding elements to a variable Map, you do not need to generate a new Map, but directly add the elements to the original Map.

What val is immutable is only the pointer, which has nothing to do with the object map.

data type

data typedescribe
Byte8-bit signed complement integer. The range of values is - 128 to 127
Short16 bit signed complement integer. The range of values is - 32768 to 32767
Int32-bit signed complement integer. The range of values is - 2147483648 to 2147483647
Long64 bit signed complement integer. The value range is - 9223372036854775808 to 9223372036854775807
Float32-bit, IEEE 754 standard single precision floating-point number
Double64 bit IEEE 754 standard double precision floating point number
Char16 bit unsigned Unicode character with interval value of U+0000 to U+FFFF
StringCharacter sequence
Booleantrue or false
UnitIndicates no value, which is equivalent to void in other languages. The result type used as a method that does not return any results. Unit has only one instance value, written as ().
Nullnull or empty reference
NothingNothing type is at the bottom of Scala's class hierarchy; It is a subtype of any other type.
AnyAny is a superclass of all other classes
AnyRefAnyRef class is the base class of all reference classes in Scala

Functional programming

Higher order function

Higher order functions are functions that use other functions as arguments or return a function as a result. In Scala, functions are "first-class citizens".

Simple example
val list=List(1,2,3,4)

val function= (x:Int) => x*2

val value=list.map(function)

Method is a function
def main(args: Array[String]): Unit = {
    val list=List(1,2,3,4)
    val value=list.map(function)
}

def function   (x:Int)=x*2
Function that returns the function
def calculate(symbol:String): (String,String)=>String ={
    symbol match {
      case "Splicing mode 1" => (a:String,b:String)=> s"Splicing mode 1:$a , $b"
      case "Splicing mode 2" => (a:String,b:String)=> s"Splicing mode 2: $b , $a"
    }
  }
val function: (String, String) => String = calculate("Splicing mode 2")

println(function("big data", "Left and right hands"))

Anonymous function

The syntax for defining anonymous functions in Scala is very simple. The left side of the arrow is the parameter list and the right side is the function body.

After using anonymous functions, our code becomes more concise.

var inc = (x:Int) => x+1

var x = inc(7)-1

It can also have no parameters

var user = () => println("Big data left and right") 

closure

A closure is a function whose return value depends on one or more variables declared outside the function.

Generally speaking, closures can be simply regarded as another function that can access local variables in a function.

The simple understanding is that the variables inside the function can still be accessed from the outside when they do not act on.

val function= (x:Int) => x*2

The essence of closure is the mixing of code and nonlocal variables

Closure = code + nonlocal variables used

val fact=2
val function= (x:Int) => x*fact

Function coritization

Coriolism refers to the process of changing the original function that accepts two parameters into a new function that accepts one parameter. The new function returns a function with the original second parameter as the parameter.

First define a simple
def add(x:Int,y:Int)=x+y

use

add(1,2)
Function deformation (this method is called coritization)
def add(x:Int)(y:Int) = x + y

use

add(1)(2)
Implementation process

add(1)(2) actually calls two ordinary functions (non Coriolis functions) in turn

The first call uses a parameter x and returns the value of a function type.

The value of this function type is called a second time with parameter y.

Receive one x Is a parameter that returns an anonymous function

Receive one Int Type parameter y,The function body is x+y. 

def add(x:Int)=(y:Int)=>x+y

(1)
val result = add(1)  // result= (y:Int)=>1+y

(2)
val sum = result(2)

(3)
sum=3

object-oriented

Classes and objects

A class is an abstraction of an object, and an object is a concrete instance of a class. Classes are abstract and do not occupy memory, while objects are concrete and occupy storage space. Class is a blueprint for creating objects. It is a software template that defines methods and variables included in specific types of objects.

Class can have class parameters

Class parameters can be used directly in the body of the class. Class parameters can also be prefixed with var and decorated with private, protected and override. The scala compiler collects class parameters and creates the main constructor of the class with the same parameters., And compile any code inside the class that is neither a field nor a method definition into the main constructor.

class Test(val a: Int, val b: Int) {
    // 
}
Sample class

case class is generally translated into sample class. It is a special class that can be optimized for pattern matching.

When a class is called case class. It has the following functions:

  1. If the parameter in the constructor is not declared as var, it defaults to val.
  2. Automatically create the associated object, and implement the sub apply method in it, so that we can create the object without using new directly.
  3. The companion object will also help us implement the unapply method, so that we can apply case class to pattern matching.
  4. Implement your own toString, hashCode, copy and equals methods
case class person(
    name:String,
    age:Int
)
Objects and companion objects

Scala singleton object is very important. It does not have static classes, static members and static methods as in Java, but Scala provides an object object, which is similar to Java's static class. Its members and methods are static by default.

Defining a singleton object does not mean defining a class, so you can't use it to create a new object. When a singleton object shares the same name with a class, it is called the companion object of the class.

Class and its associated objects must be defined in the same source file. Class is called the companion class of this singleton object.

Class and its companion objects can access each other's private members.

object Test {
  private var name="big data"

  def main(args: Array[String]): Unit = {
    val test = new Test()
    println(test.update_name())
  }
}

class Test{
  def update_name(): String ={
    Test.name="Left and right hands"
    Test.name
  }

}
Trait

scala trait is equivalent to the java interface. In fact, it is more powerful than the interface.
Unlike interfaces, it can also define the implementation of properties and methods.

In general, scala classes can only inherit a single parent class, but if it is a trait, it can inherit multiple. From the result, it implements multiple inheritance (keyword with). In fact, scala trait is more like an abstract class of java.

object Test extends UserImp with AddressImp {
  override def getUserName(): String = ???

  override def getAddress(): String = ???
}

trait UserImp{
  def getUserName():String 
}

trait AddressImp{
  def getAddress():String
}

pattern matching

Take java switch as an example. java switch only does some basic type matching, and then performs some actions, and there is no return value.

scala's pattern matching match is much more powerful. In addition to matching values, it can also match types.

def calculate(symbol:String): (String,String)=>String ={
    symbol match {
      case "Splicing mode 1" => (a:String,b:String)=> s"Splicing mode 1:$a , $b"
      case "Splicing mode 2" => (a:String,b:String)=> s"Splicing mode 2: $b , $a"
    }
  }
To my surprise (just a few lines)
Quick row

def quickSort(list: List[Int]): List[Int] = list match {
    case Nil => Nil
    case List() => List()
    case head :: tail =>
      val (left, right) = tail.partition(_ < head)
      quickSort(left) ::: head :: quickSort(right)
  }
  
Merge

def merge(left: List[Int], right: List[Int]): List[Int] = (left, right) match {
    case (Nil, _) => right
    case (_, Nil) => left
    case (x :: xTail, y :: yTail) =>
      if (x <= y) x :: merge(xTail, right)
      else y :: merge(left, yTail)
}

Implicit conversion

Scala provides implicit conversion and implicit parameter functions, which are very characteristic functions. It is a function that programming languages such as Java do not have. It allows you to manually specify and convert objects of one type to objects of other types. Through these functions, very powerful and special functions can be realized.

rule

(1) Before using implicit conversion, you need to use import to reference the implicit conversion to the current scope or define the implicit conversion in the scope.

(2) Implicit conversions can only be operated if no other conversions are available. If more than one implicit conversion function is defined for the same source type in the same scope, if multiple implicit conversion functions can match, the compiler will report an error. Therefore, please remove unnecessary implicit definitions when using.

Implicit conversion of data types

String type cannot be automatically converted to Int type, so when a variable or constant of Int type is given a value of string type, the compiler will report an error. But

  implicit def strToInt(str: String) = str.toInt
  def main(args: Array[String]): Unit = {
    val a:Int="100"
    
    print(a)
  }

Implicit conversion of parameters

The so-called implicit parameter refers to defining an implicit modified parameter in a function or method. At this time, Scala will try to find a specified type of implicit modified object, that is, implicit value, and inject parameters.

object Test {
  private var name="big data"
  implicit val test = new Test

  def getName(implicit test:Test): Unit ={
    println(test.update_name())
  }
  def main(args: Array[String]): Unit = {
    getName
  }
}

class Test{
  def update_name(): String ={
    Test.name="Left and right hands"
    Test.name
  }

}

Topics: Scala Interview flink