在本教程中,我们将学习如何创建隐式函数。通过使用隐式函数,我们可以为几乎任何类型或类提供扩展方法或函数。 顾名思义,Scala从一开始就是可扩展的。隐式的用法,是Scala提供的特性之一,通过它我们可以轻松地向任何类型或类添加扩展方法或函数。
在下面这个示例中,我们将扩展String类,使其具有isFavoriteFruit()函数。
object demo04 {
// 创建一个简单的包装类FruitString,
// 它将使用String类型作为参数,然后提供一个isFavoriteDonut()函数。
class FruitString(s: String) {
def isFavoriteFruit: Boolean = s == "苹果"
}
// 创建隐式函数转换字符串到包装字符串类
// 将隐式函数或转换封装到一个使用对象的单例中是一个很好的实践
// 义一个名为stringToFruitString的隐式函数,该函数将以String类型作为参数,
// 并通过名为FruitString的String包装器类的新实例将其连接起来。
object FruitConverstions {
// 定义隐式函数类似于定义任何其他函数,只是使用implicit关键字作为函数签名的前缀。
implicit def stringToFruitString(s: String) = new FruitString(s)
}
def main(args: Array[String]): Unit = {
// 为了使用隐式String函数将String类型转换为FruitString类型,
// 必须在作用域内使用隐式函数。这可以使用import关键字实现
import FruitConverstions._
// 创建两个String类型的不可变值,分别代表不同的水果
val apple = "苹果"
val gooseberry = "弥猴桃"
// 访问 isFavoriteFruit()
println(s"苹果是不是最喜欢的水果 = ${apple.isFavoriteFruit}")
println(s"弥猴桃是不是最喜欢的水果 = ${gooseberry.isFavoriteFruit}")
}
}
执行上面的代码,输出内容如下:
苹果是不是最喜欢的水果 = true
弥猴桃是不是最喜欢的水果 = false
Tip:
-
将隐式函数和值封装到Object或Package Object中是一个很好的实践。
-
Scala Predef类利用隐式函数提供现成的转换,比如Java从/到Scala的转换。
隐式值
隐式参数的使用是Scala中如何实现依赖注入的一个例子。事实上,依赖注入是内置在Scala语言中的,这样就不必导入另一个第三方库。
在下面的示例中,定义了一个函数,带有一个隐式参数。在执行时,Scala编译器将寻找Double类型的隐式值。如果作用域中没有隐式值,则会得到一个编译器错误。因此,我们将在代码库中某处定义一个Double类型的隐式值。定义隐式值类似于使用val关键字定义任何其他值,只是在val关键字前面加上implicit关键字。
object demo {
def main(args: Array[String]): Unit = {
// 定义一个Double类型的隐式值
implicit val discount: Double = 0.1
println(s"所有客户将收到一个 ${discount * 100}% 折扣")
println(s"""加上5个苹果的折扣价 = ${totalCost("苹果", 5)}""")
}
// 定义一个带有隐式参数的函数
// 在执行时,Scala编译器将寻找Double类型的隐式值。
// 如果作用域中没有隐式值,则会得到一个编译器错误。
def totalCost(fruitType: String, quantity: Int)(implicit discount: Double): Double = {
println(s"计算 $quantity 个 $fruitType 的价格")
val totalCost = 2.50 * quantity * (1 - discount)
totalCost
}
}
如何定义一个函数接受多个隐式参数?
定义额外的隐式参数类似于定义任何其他参数,只需使用逗号分隔参数。在下面的例子中,我们扩展totalCost()函数,以接受一个隐含的String类型参数,该参数表示水果商店的名称。
因此,需要首先定义另一个String类型的隐式值,以便它在调用totalCost()函数之前处于作用域中。
object demo {
def main(args: Array[String]): Unit = {
// 定义一个Double类型的隐式值
implicit val discount: Double = 0.1
println(s"所有客户将收到一个 ${discount * 100}% 折扣")
println(s"""加上5个苹果的折扣价 = ${totalCost("苹果", 5)}""")
implicit val storeName: String = "农夫果园"
println(s"""加上5个苹果的折扣价 = ${totalCost2("苹果", 5)}""")
}
// 定义一个带有隐式参数的函数
// 在执行时,Scala编译器将寻找Double类型的隐式值。
// 如果作用域中没有隐式值,则会得到一个编译器错误。
def totalCost(fruitType: String, quantity: Int)(implicit discount: Double): Double = {
println(s"计算 $quantity 个 $fruitType 的价格")
val totalCost = 2.50 * quantity * (1 - discount)
totalCost
}
// 多个隐式参数
def totalCost2(fruitType: String, quantity: Int)(implicit discount: Double, storeName: String): Double = {
println(s"[$storeName] 计算 $quantity 个 $fruitType 的价格")
val totalCost = 2.50 * quantity * (1 - discount)
totalCost
}
}
如何手动传递隐式参数
在极少数情况下,我们可能不得不手动传递隐式参数值。这可以通过下面所示的另一对括号传递隐式参数来实现。
// 手动传递隐式参数
println(s"""加上5个苹果的折扣价, 手动传参 = ${totalCost2("苹果", 5)(0.1, "农夫果园")}""")
© 版权声明
本站网络名称:
知趣
本站永久网址:
https://www.qubaa.top
网站侵权说明:
本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长删除处理。
1 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
2 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
3 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
1 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
2 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
3 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
THE END
暂无评论内容