5.7 类型化函数,多态函数和符号函数

类型化函数

所谓类型化函数,指的是在调用函数时可以指定参数的类型。Scala的类型化函数通过变量的使用提供了更大的灵活性。那么,如何定义一个泛型类型函数将指定其参数的类型?

下面我们将创建一个类型化函数,它将指定一个T类型的泛型参数,如下所示:

object demo {

// 应用折扣的泛型函数
def applyDiscount[T](discount: T) {
  discount match {
    case d: String =>
      println(s"在数据库中查找 $d 的百分比折扣")

    case d: Double =>
      println(s"$d 折扣优惠")

    case _ =>
      println("不支持的折扣类型")
  }
}

def main(args: Array[String]): Unit = {
  // 要调用类型化函数applyDiscount(),必须提供其参数的类型。
  applyDiscount[String]("COUPON_123")
  applyDiscount[Double](10)
  applyDiscount[Int](10)
}
}

执行上面的代码,输出内容如下:

在数据库中查找 COUPON_123 的百分比折扣
10.0 折扣优惠
不支持的折扣类型

虽然可以依赖Scala的类型推断来推断函数参数的类型,但一般来说,显式指定参数类型是一个很好的实践。

多态函数

多态函数指的是具有泛型返回类型的函数。在多态函数中,我们可以指定参数的类型以及函数的返回类型。

下面让我们定义另一个本质上是多态的函数。我们将函数命名为applyDiscountWithReturnType(),它将接受泛型类型T作为其折扣参数。但是它也会返回一个类型为T的Sequence。

object demo {

// 定义一个多态函数
// 它将接受泛型类型T作为其折扣参数。但是它也会返回一个类型为T的Sequence。
def applyDiscountWithReturnType[T](discount: T): Seq[T] = {
  discount match {
    case d: String =>
      println(s"在数据库中查找 $d 的百分比折扣")
      Seq[T](discount)

    case d: Double =>
      println(s"$d 折扣优惠")
      Seq[T](discount)

    case d @ _ =>
      println("不支持的折扣类型")
      Seq[T](discount)
  }
}

def main(args: Array[String]): Unit = {
  // 使用不同的类型,即String、Double和Char来分别调用多态函数
  println(s"带String参数调用结果 = ${applyDiscountWithReturnType[String]("COUPON_123")}")

  println()
  println(s"带Double参数调用结果 = ${applyDiscountWithReturnType[Double](10.5)}")

  println()
  println(s"带Char参数调用结果 = ${applyDiscountWithReturnType[Char]('U')}")
}
}

执行以上代码,输出结果如下:

在数据库中查找 COUPON_123 的百分比折扣
带String参数调用结果 = List(COUPON_123)

10.5 折扣优惠
带Double参数调用结果 = List(10.5)

不支持的折扣类型
带Char参数调用结果 = List(U)

为简单起见,我们将为模式匹配中的每一种情况返回一个类型为T的新序列。对于调用多态函数applyDiscountWithReturnType()时使用的每个指定类型,该函数还返回相同类型的Sequence序列。

关于@运算符

@运算符允许将匹配的模式绑定到变量。请看下面的示例:

object demo {

def main(args: Array[String]): Unit = {

  // 例如,考虑以下情况:
  val o: Option[Int] = Some(2)

  // 可以很容易地提取内容:
  o match {
    case Some(x) => println(x)
    case None =>
  }

  // 但是,如果想要的不是Some的内容,而是Option本身呢?
  // 这将通过以下方式实现:
  o match {
    case x @ Some(_) => println(x)
    case None =>
  }
   
}

}

执行上面的代码,输出结果如下:

2
Some(2)

注意,@ 可用于任何级别,而不仅仅是顶级的匹配。

符号函数

符号函数指的是仅使用符号而不是字母命名的函数。当必须创建特定于域的语言语法时,Scala的这个特性是一个很好的构建块。

定义名称为符号的函数本质上与定义任何其他函数相同。这个函数没有名称,而是用一些符号来定义。例如:

def -(discount: Double): Double = {
totalCost - discount
}

调用一个函数,其名称只是一个符号,就像上面步骤中的-函数一样,与调用任何其他函数没有什么不同。

println(s"调用函数 - = ${donutCostCalculator.-(10.5)}")

Scala允许使用如下所示的操作符样式来调用函数:

println(s"调用函数-使用操作符样式表示法 = ${donutCostCalculator - 10.5}")

使用操作符样式调用函数与调用函数没有太大区别,只是不需要指定点(.)。当调用函数名只是符号时,使用操作符风格更清晰。

既然已经知道了如何定义名称只是符号的函数,那么让我们创建另一个名为+++的函数。

def +++(taxAmount: Double): Double = {
totalCost + taxAmount
}

完整代码如下:

object demo {

val totalCost = 100

// 定义名称为符号的函数本质上与定义任何其他函数相同。这个函数没有名称,而是用一些符号来定义。例如:
def -(discount: Double): Double = {
totalCost - discount
}

// 既然已经知道了如何定义名称只是符号的函数,那么创建另一个名为+++的函数。
def +++(taxAmount: Double): Double = {
totalCost + taxAmount
}

def main(args: Array[String]): Unit = {
// 调用一个函数,其名称只是一个符号,就像上面步骤中的-函数一样,与调用任何其他函数没有什么不同。
println(s"调用函数 - = ${demo07.-(10.5)}")

// Scala允许使用如下所示的操作符样式来调用函数
// 使用操作符样式调用函数与调用函数没有太大区别,只是不需要指定点(.)。
// 当调用函数名只是符号时,使用操作符风格更清晰。
println(s"调用函数-使用操作符样式表示法 = ${demo07 - 10.5}")

// 加税计算的方法
println(s"调用+++函数 = ${demo07 +++ 13.5}")
}
}

执行以上代码,输出结果如下:

调用函数 - = 89.5
调用函数-使用操作符样式表示法 = 89.5
调用+++函数 = 113.5
© 版权声明
THE END
喜欢就支持一下吧
点赞114赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

夸夸
夸夸
还有吗!没看够!
取消
昵称表情代码图片

    暂无评论内容