官术网_书友最值得收藏!

  • Scala Design Patterns
  • Ivan Nikolov
  • 507字
  • 2021-07-16 12:57:28

Functions and classes

In Scala, every value is an object. Functions are first class values, which also makes them objects of their respective classes. The following figure shows the Scala unified type system and how this is achieved. It is adapted from http://www.scala-lang.org/old/sites/default/files/images/classhierarchy.png and represents an up-to-date view of the model (some classes such as ScalaObject have disappeared, as we have already mentioned before).

As you can see, Scala does not have the same concept of primitive types that Java has and all types are ultimately subtypes of Any.

Functions as classes

The fact that functions are classes means that they can be freely passed to other methods or classes as if they were just values. This leads to improving the expressiveness of Scala and making it much easier to achieve things, such as callbacks, than in other languages such as Java.

Function literals

Let's have a look at an example:

class FunctionLiterals { 
  val sum = (a: Int, b: Int) => a + b 
} 

object FunctionLiterals { 
  
  def main(args: Array[String]): Unit = { 
    val obj = new FunctionLiterals 
    System.out.println(s"3 + 9 = ${obj.sum(3, 9)}") 
  } 
}

Here we can see how the sum field of the FunctionLiterals class is actually assigned a function. We can assign any function to a variable and then call it as if it was a function (essentially invoking its apply method). Functions can also be passed as parameters to other methods. Let's add the following to our FunctionLiterals class:

def runOperation(f: (Int, Int) => Int, a: Int, b: Int): Int = { 
  f(a, b) 
}

We can then pass the required function to runOperation, as follows:

obj.runOperation(obj.sum, 10, 20)
obj.runOperation(Math.max, 10, 20)
Functions without syntactic sugar

In the preceding example, we just used syntactic sugar. In order to understand exactly what happens, we will show to what the function literals are converted. They basically represent extensions to the FunctionN trait where N is the number of parameters. The implementations of the literals are invoked using the apply method (whenever a class or an object has an apply method, it can be implicitly invoked just using parentheses after the object name or instance and passing the required parameters, if any). Let's see the equivalent implementation to our previous example:

class SumFunction extends Function2[Int, Int, Int] { 
  override def apply(v1: Int, v2: Int): Int = v1 + v2 
} 

class FunctionObjects { 
  val sum = new SumFunction 
  
  def runOperation(f: (Int, Int) => Int, a: Int, b: Int): Int = 
    f(a, b) 
} 

object FunctionObjects { 
  
  def main(args: Array[String]): Unit = { 
    val obj = new FunctionObjects 
    System.out.println(s"3 + 9 = ${obj.sum(3, 9)}") 
    System.out.println(s"Calling run operation: ${obj. runOperation(obj.sum, 10, 20)}") 
    System.out.println(s"Using Math.max: ${obj.runOperation(Math.max, 10, 20)}") 
  } 
}

Increased expressivity

As you can see from the examples, unifying classes and functions leads to increased expressivity and we can easily achieve various things such as callbacks, lazy parameter evaluation, centralized exception handling, and others and without writing extra code and logic. Moreover, functions as classes mean that we can extend them to provide extra functionality.

主站蜘蛛池模板: 昭觉县| 嘉定区| 讷河市| 来凤县| 诸暨市| 甘肃省| 荥经县| 渑池县| 嘉义县| 渭南市| 徐闻县| 盐城市| 岑巩县| 安远县| 枣阳市| 阜康市| 祁门县| 霍邱县| 昌图县| 元朗区| 泸州市| 山阴县| 齐齐哈尔市| 云浮市| 会同县| 正镶白旗| 肥城市| 响水县| 泽库县| 安陆市| 宁津县| 墨竹工卡县| 赤峰市| 宿松县| 永福县| 惠安县| 明光市| 和平区| 土默特左旗| 新源县| 韶山市|