【Scala之旅】隐式参数和隐式转换

news/2023/12/1 7:14:31

本节翻译自

  • Implicit Parameters
  • Implicit Conversions

综述:隐式转换和隐式参数是Scala的两个功能强大的工具,在幕后处理很有价值的工作。利用隐式转换和隐式参数,你可以提供优雅地类库,对类库的使用者隐藏那些枯燥乏味的细节。

隐式参数

一个方法可以有一个隐式 参数列表,在参数列表的开始处由 implicit 关键字标记。如果参数列表中的参数没有像往常那样传递,Scala 会查看它是否可以获得正确类型的隐式值,如果可以,则自动传递它。

Scala 将寻找的这些参数分为两类:

  • 首先,Scala 将寻找隐式定义和隐式参数,它们可以在带有隐式参数块的方法被调用(不带前缀)时被直接访问。
  • 然后,它会查找隐含在与隐式候选类型关联的所有伴生对象中的成员。

在常见问题解答中可以找到有关 Scala 寻找隐含位置的更详细指南

在下面的例子中,我们定义了一个方法 sum,它使用 Monoid 的 addunit 操作来计算一个元素列表的和。请注意,隐式值不能是顶级的。

abstract class SemiGroup[A] {
  def add(x: A, y: A): A
}
abstract class Monoid[A] extends SemiGroup[A] {
  def unit: A
}
object ImplicitTest extends App {
  implicit object StringMonoid extends Monoid[String] {
    def add(x: String, y: String): String = x concat y
    def unit: String = ""
  }
  implicit object IntMonoid extends Monoid[Int] {
    def add(x: Int, y: Int): Int = x + y
    def unit: Int = 0
  }
  def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
    if (xs.isEmpty) m.unit
    else m.add(xs.head, sum(xs.tail))

  println(sum(List(1, 2, 3)))       // uses IntMonoid implicitly
  println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly
}

Monoid 在这里定义了一个名为 add 的操作,它将一对 A 组合起来并返回另一个 A,以及一个称为 unit 的操作,它可以创建一些(特定的)A

为了显示隐式参数如何工作,我们首先分别为字符串和整数定义 Monoid StringMonoidIntMonoidimplicit 关键字指示相应对象可以被隐式地使用。

方法 sum 输入 List[A] 并返回一个 A,它从 unit 中获取最初的 A,并将列表中的每个下一个 A 与具有 add 方法的下一个 A 组合在一起。使参数 m 隐含在这里意味着我们只需要在我们调用方法时提供 xs 参数,如果 Scala 可以找到用于隐式 m 参数的隐含 Monoid[A]

在我们的 main 方法中,我们调用了两次 sum,并只提供了 xs 参数。现在 Scala 会在上面提到的范围中寻找隐含的。第一次调用 sum 时,会为 xs 传递一个 List[Int],这意味着 AInt。 含有 m 的隐含参数列表被省略,因此 Scala 会查找类型为 Monoid[Int] 的隐式参数。 刚刚所讲的第一条规则是

首先,Scala 将寻找隐式定义和隐式参数,它们可以在带有隐式参数块的方法被调用(不带前缀)时被直接访问。

intMonoid 是一个隐式定义,可以直接在 main 中访问。它也是正确的类型,所以它会自动传递给 sum 方法。

第二次求和传递一个 List[String],这意味着 AString。隐式查找将采用与 Int 相同的方式,但是这次将找到 stringMonoid,并将其自动作为 m 传递。

下面是Scala程序的输出:

6
abc

隐式转换

从类型 ST 类型的隐式转换由函数类型 S => T 的隐式值定义,或者通过隐式方法可转换为这种类型的值。

隐式转换适用于两种情况:

  • 如果表达式 eS 类型,S 不符合表达式的期望类型 T
  • S 类型的 e 的一个选择e.m中,如果选择器 m 并不是 S 里面的成员。

在第一个例子中,一个转换 c 被搜索,它适用于 e,并且其结果类型符合 T。在第二个例子中,一个转换 c 被搜索,它适用于 e,其结果包含一个名为 m 的成员。

如果隐式方法 List[A] => Ordered[List[A]]Int => Ordered[Int] 在范围内,则对 List[Int] 类型的两个列表的以下操作是合法的:

List(1, 2, 3) <= List(4, 5)

隐式方法 Int => Ordered[Int] 通过 scala.Predef.intWrapper 自动提供。下面提供了一个隐式方法 List[A] => Ordered[List[A]] 的示例。

import scala.language.implicitConversions

implicit def list2ordered[A](x: List[A])
    (implicit elem2ordered: A => Ordered[A]): Ordered[List[A]] =
  new Ordered[List[A]] { 
    //replace with a more useful implementation
    def compare(that: List[A]): Int = 1
  }

隐式导入的对象 scala.Predef 声明了几个预定义的类型(例如 Pair)和方法(例如 assert),但也包含若干隐式转换。

例如,当期望调用 java.lang.Integer 的 Java 方法时,您可以自由地将它传递给 scala.Int。这是因为 Predef 包含以下隐式转换:

import scala.language.implicitConversions

implicit def int2Integer(x: Int) =
  java.lang.Integer.valueOf(x)

如果在编译隐式转换定义时不加区别地使用编译器警告的话,隐式转换可能会有陷阱。

要关闭这些警告,请采取以下行动:

  • 在隐式转换定义的范围内导入 scala.language.implicitConversions
  • -language:implicitConversions 调用编译器

编译器应用转换时就不会发出警告了。


http://www.niftyadmin.cn/n/2417735.html

相关文章

电脑扫描二维码_智能设备中条码扫描模组是如何运作的呢?

对于条码扫描模组如何工作&#xff0c;很多人都不是很清楚其中的工作原理。了解它之前&#xff0c;要知道它可以干什么&#xff0c;条码扫描模组广泛应用于自动识别领域的核心识别部件&#xff0c;它是对条码扫描器进行二次开发的关键零件之一&#xff0c;具备完整独立的条码扫…

mysql主键归零_mysql自增主键归零的方法

最近老是要为现在这个项目初始化数据&#xff0c;搞的很头疼&#xff0c;而且数据库的Id自增越来越大&#xff0c;要让自增重新从1开始&#xff1a;那么就用下面的方法吧&#xff1a;方法一&#xff1a; 如果曾经的数据都不需要的话&#xff0c;可以直接清空所有数据&#xff0…

[PAT乙级]1028 人口普查 (20 分) [查找元素]

文章目录二刷代码我的代码柳神代码二刷代码 学习&#xff1a; 字符串居然可以直接比较带 / 的数字的大小&#xff0c;非常的nice呀。 #include<iostream> #include<vector> #include<algorithm> #include<string> using namespace std; struct node{…

鼠标在滑块上滚轮控制_滚轮导轨的优势特点

滚轮导轨具有如下优点&#xff1a;适合恶劣环境下的使用&#xff1a;滚轮中的轴承的滚动体&#xff0c;和导轨并不直接接触&#xff0c;同时轴承具有很好的密封性&#xff1b;Cubic采用的V型导向技术&#xff0c;使得V型滚轮通过“刮擦”运动&#xff0c;可以把灰尘、切屑等杂质…

linux mysql 命令行安装_Linux命令安装Mysql

关键步骤&#xff1a;4.创建用户组和用户groupadd mysqluseradd -r -g mysql mysql5.修改权限chown -R mysql:mysql ./6.安装数据库./script/mysql_install_db —usermysql7.修改当前目录拥有者chown -R root:root ./chowd -R mysql:mysql data8.添加mysql为系统服务cp support…

蓝桥杯--求和

1.题目 2.思路 这个题好像做过 应该做过 蓝桥杯的题有的题大同小异 3.代码 public class J69 { public static void main(String[] args) {int sum0;for(int i1;i<2020;i) {String str""i;for(int j0;j<str.length();j) {if(str.charAt(j)2||str.charAt(j)0|…

BIND和DNS名称解析

一、DNS和Bind1.DNS功能&#xff1a;将主机名和ip地址进行一一对应&#xff0c;通过主机名可以解析到目标主机的ip地址(正向解析)&#xff0c;也可以通过ip地址解析到主机名(反向解析)。主机名到IP地址的映射有两种&#xff1a;静态映射&#xff1a;每台设备上都有主机到ip映射…

[PAT乙级]1032 挖掘机技术哪家强 (20 分)[查找元素]

三刷代码 #include<iostream> #include<map> using namespace std; int main(){int n;cin>>n;map<int,int> m;for(int i0;i<n;i){int t1,t2;cin>>t1>>t2;m[t1]t2;}int maxid,maxnum-1;for(auto itm.begin();it!m.end();it){if(it->…

go 包依赖静态分析

2019独角兽企业重金招聘Python工程师标准>>> 生产go包依赖图 安装godepgraph go get -u github.com/kisielk/godepgraph 安装graphviz brew install graphviz 生成dot信息&#xff0c;和生产png文件 godepgraph -horizontal imguplogparse |dot -Tpng -o a.png go…

[PAT 乙级]1036 跟奥巴马一起编程 (15 分)[图形输出]

我的代码 tmd一开始在测试案例中直接输出的是“a”&#xff0c;应该输出 c变量才对&#xff0c;我说怎么一直AC不了 #include <iostream> using namespace std; int main() {char c;int n;cin>>n>>c;int t n / 2 n % 2;for(int j0;j<n;j){cout<<…

vue组件之间的通信, 父子组件通信,兄弟组件通信

组件通讯包括&#xff1a;父子组件间的通信和兄弟组件间的通信。在组件化系统构建中&#xff0c;组件间通信必不可少的。 父组件--> 子组件 1. 属性设置 父组件关键代码如下&#xff1a; <template><Child :child-msg"msg"></Child> </templ…

微信转账2020假图片_2020个性头像图片大全微信

长按保存 点击放大图片很大&#xff0c;请在 W i f i 下浏览✎人生不能太过圆满 求而不得未必是遗憾 ?✎日后与风海阳光相爱 拂过我的每一寸肌肤倾听我的每一句私语照耀我的每一处灵魂? ✎爱到八分绝对刚刚好。所有的期待和希望都只有七八分&#xff0c;剩下两三分用来爱…

蓝桥杯--求值

1.题目 2.思路 这个题我感觉的难点就是怎么判断一个数有几个约数 而不是连着 所以 计算一个数 就重新置零 在进行比较 结果才正确 具体代码体现 3.代码 public class J70 {public static void main(String[] args) {int j0;for(int i1;true;i) {for(int k1;k<i;k) {if(i%k…

蓝桥杯--次数差

1.题目 2.思路 这个题 有一个点就是不能将零作为最小值 因为国王不重视他们 思路和前面一个词类似 我记得前面那个题是计算单词出现次数最多的 这个题大同小异 基本的思想是类似的 我们先把26个字母找一个整形数组储存起来 用字母下标表示每一个字母 然后我们可以利用 Arrays.s…

linux内核支持U-disk和U转串

配置内核 make menuconfig&#xff0c;选中device驱动 Device Drivers ---->USB support--->USB Serial Converter support---->(1)USB Generic Serial Driver. (2)USB FTDI Single Port Serial Driver.(FTDI芯片驱动)(3)USB Prolific 2303 Single Port Serial Driver…

vs和mysql字符集_VS下用c++连接mysql,字符编码格式转换

这两天在VS2010下用c连接mysql数据库&#xff0c;开始的时候能成功读取数据库中的INT型数据&#xff0c;但对其中的varchar类型无法正常读取(数据库采用utf-8编码)&#xff0c;读取出来的都是乱码。后来经过在网上搜索和思考&#xff0c;终于解决了。整理如下。问题解析&#x…
最新文章