关于Scala的相关函数

94 阅读4分钟

一个函数是执行某种任务的表达式的集合。我们可以在scala中把一段代码分成独立的函数,每个函数都必须执行特定的任务。我们用函数把一些常见的重复性任务放到一个函数中,这样就不用为不同的输入反复编写相同的代码,而只需调用函数即可。一个函数是一个完整的对象,我们可以把它储存在一个变量中。它使调试和修改代码变得更加容易。Scala函数是一流的 价值,因为Scala有丰富的内置函数,它也可以让我们创建自己的。

//Function Example
def exampleFunction(firstParameter: Int, secondParameter: Int): Int = {
  val temp = 2 + 3
  temp
}

下面宣布的是我们如何以实例的形式编写函数的语法。

Scala Function Declaration Example

IntelliJ IDEA上的Scala函数

如何在Scala中使用函数

一个函数可以执行单个或多个任务。要使用任何函数,我们需要调用它。Scala为我们提供了不同的方法来调用一个函数,即我们可以直接调用它们,也可以通过使用类的实例来调用。

正如我们在上面的例子中看到的那样。让我们来看看类实例调用函数的例子。

Scala Function Class Instance

类实例的函数调用

现在让我们来谈谈我们如何调用这些函数。

函数调用的类型

按值调用

函数参数默认为按值调用。在按值调用中,我们在函数自己评估之前计算出表达式的精确值,之后在整个函数定义中使用相同的值。

按名称调用

在按名调用中,我们使用这个=>符号来表示函数按名调用,每次调用参数时都会评估参数。

按值调用和按名调用的代码片段。

让我们看看上面的代码中发生了什么。

当CallByValue函数被调用时,我们可以看到函数的输出在每次调用时都是一样的,但在CallByName的情况下,输出是不同的,因为函数每次被使用时都会评估参数。

虽然这两种是调用函数的方式,但函数可以是带参数的,也可以是不带参数的。

//With Parameter
def WithParameter(Parameter: Int): Int = {
  val temporaryVariable = 2 * 3
  temporaryVariable
}
//Without Parameter
def WithoutParameter: Int = {
  val temporaryVariable = 2 * 3
  temporaryVariable

Scala中的函数类型

以下是Scala中不同类型的函数

Currying函数

在Scala中,Currying是一种将接受多个参数的函数转化为只有一个参数的函数链的方式。

//Currying Function with a single argument

object CurryingFunction
{
    
    def addNumber(firstParameter: Int)(secondParameter: Int) => firstParameter + secondParameter;
    def main(args: Array[String])
    {
        println(addNumber(20)(19));
    }
}

匿名函数

匿名函数是一种不包含名称的函数类型。它是一种轻量级的函数,当我们想在一行代码中创建一个函数时,它很有用。另外,匿名函数是功能字面,在运行时,它们会实例化为对象,称为函数值。

//Anonymous Function with Parameter.

object AnonymousFunction {

  def main(args: Array[String]) {

    val firstFunctionWithParameter = (FirstNumber:Int, SecondNumber:Int) => FirstNumber + SecondNumber
    val secondFunctionWithParameter = (_:Int) + (_:Int)
    println(firstFunctionWithparameter(8,6))
    println(secondFunctionWithParameter(5,10))
  }

在上面的第一个语法中,=>是一个转换器。变换器用于将符号左边的参数列表转换为使用右边的表达式的新结果。

在上面的第二种语法中,_(下划线)字符是一个通配符,是代表在匿名函数中只出现一次的参数的一种速记方式。

嵌套函数

在Scala中,我们可以在另一个函数中定义一个Scala函数。它主要用于尾部递归,也可用于避免使用循环。

//Nested Function

object NestedFunction {
  def maxAndMin(a: Int, b: Int) = {
    def maxValue() = {
      if(a > b) {
      println("Max is: " + a)
      }
      else {
      println("Max is: " + b)
      }
    }
    def minValue() = {
      if (a < b) {
      println("Min is: " + a)
      }
      else {
      println("Min is: " + b)
      }
     }
     maxValue();
     minValue();
  }
maxAndMin(5, 6)
}

闭合函数

Scala闭合函数使用一个或多个自由变量,我们在闭合函数之外声明自由变量,不把它作为这个函数的参数,这个函数的返回值取决于这些自由变量。

//Closure Function

object ClosureFunction {
  def main(args: Array[String])
  {
    println( "Final_Sum(1) value = " + sum(1))
    println( "Final_Sum(2) value = " + sum(2))
    println( "Final_Sum(3) value = " + sum(3))
  }
 var a = 4
 val sum = (b:Int) => b + a
}

递归函数

递归在函数式编程中很常见,因为它涉及到将一个问题分解成小块。为最小的部分寻找解决方案,并将其整合到最后一次调用中。为了实现这一目标,递归函数将一次又一次地调用自己,直到满足预定义的情况下停止。递归通过将值存储在所谓的Stackframe中使之成为可能。

//Recursive Function

object Factorial
{
    def fact(n:Int): Int=
    {
        if(n <= 1) 1
        else n * fact(n - 1)
    }
      
    def main(args:Array[String])
    {
        println(fact(10))
    }
}

在上面的代码块中,如果输入的数字高于它们,就会出现堆栈溢出的问题。

尾部递归

如果一个递归函数的递归调用是该函数做的最后一件事,那么该函数就是尾部递归。尾部递归函数比递归函数更好,因为编译器可以优化尾部递归。尾部递归不保留前一个状态的记录,这就是它如何避免StackOverflow的问题。

//Tail Recusion
import scala.annotation.tailrec
  
object tailRecursion
{
    def factorial(n: Int): Int =
    {
      @tailrec 
      def factorialAcc(acc: Int, n: Int): Int =
      {
         if (n <= 1)
         acc
         else 
         factorialAcc(n * acc, n - 1)
      }
    factorialAcc(1, n)
    }
      
    def main(args:Array[String])
    {
      println(factorial(5))
    }
}

总结

Scala有不同的类型和方法来声明函数,它也高度依赖于函数,因为它避免了程序中的可变性和循环的使用,但当我们需要在程序中进行迭代时,Scala中的函数有助于完成这一任务。