Scala实践13
1、隐式参数
方法可以具有隐式参数列表,由参数列表开头的implicit关键字标记。如果该参数列表中的参数没有像往常一样传递,Scala将查看它是否可以获得正确类型的隐式值,如果可以,则自动传递。
Scala将查找这些参数的位置分为两类:
- Scala将首先查找隐式定义和隐式参数,这些参数可以在调用隐式参数块的方法时直接访问(无前缀)。
- 然后,它查找与隐式候选类型关联的所有伴随对象中隐式标记的成员。
abstract class Monoid[A] {
def add(x: A, y: A): A
def unit: A
} object ImplicitTest {
implicit val stringMonoid: Monoid[String] = new Monoid[String] {
def add(x: String, y: String): String = x concat y
def unit: String = ""
} implicit val intMonoid: Monoid[Int] = new 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)) def main(args: Array[String]): Unit = {
println(sum(List(1, 2, 3))) // intMonoid
println(sum(List("a", "b", "c"))) //stringMonoid
}
}
Monoid
定义一个add
在这里调用的操作,它返回一个A
,一个unit
能够创建一些(特定)的操作。
为了说明隐式参数如何工作,首先分别定义 stringMonoid
和intMonoid
字符串和整数。该implicit
关键字指示对应的对象可以被隐式地使用。
该方法sum
接受 List[A]
并返回A
,它从初始化A开始unit
,并将A
列表中的每个下一个与该add
方法的下一个组合。使参数m
隐含在这里意味着只需要在调用方法时提供参数,如果Scala可以找到隐Monoid[A]
式m
参数用于隐式参数。
在main
方法中,调用sum
两次,并且只提供参数。Scala现在将在上述范围内寻找隐含的内容。第一次调用sum
传递List[Int]
for xs
,这意味着A
就是Int
。隐藏了隐式参数列表m
,因此Scala将查找隐式类型Monoid[Int]
。第一个查找规则读取
- Scala将首先查找隐式定义和隐式参数,这些参数可以在调用隐式参数块的方法时直接访问(无前缀)。
intMonoid
是一个可以直接访问的隐式定义。它也是正确的类型,因此它会sum
自动传递给方法。
第二次调用sum
传递List[String]
,这意味着A
就是String
。隐式查找将与使用相同的方式Int
,但这次将查找stringMonoid
,并自动传递为m
。
输出如下:
2、隐式转换
从类型S
到类型的隐式转换由T
具有函数类型的隐式值定义S => T
,或者由可转换为该类型的值的隐式方法定义。
隐式转换适用于两种情况:
- 如果表达式
e
是类型S
,并且S
不符合表达式的预期类型T
。 - 在
e.m
具有e
类型S
的选择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]] {
//替代
def compare(that: List[A]): Int = 1
}
隐式导入的对象scala.Predef
声明了常用类型(例如scala.collection.immutable.Map
别名Map
)和方法(例如assert
)的几个别名,但也有几个隐式转换。
例如,在调用期望的Java方法时java.lang.Integer
,您可以自由地传递它scala.Int
。这是因为Predef包含以下隐式转换:
import scala.language.implicitConversions implicit def int2Integer(x: Int) =
java.lang.Integer.valueOf(x)
因为如果不加选择地使用隐式转换可能会有陷阱,编译器会在编译隐式转换定义时发出警告。
要关闭警告,请执行以下任一操作:
- 导入
scala.language.implicitConversions
隐式转换定义的范围 - 使用调用编译器
-language:implicitConversions
编译器应用转换时不会发出警告。
3、多态方法
Scala中的方法可以按类型和值进行参数化。语法类似于泛型类。类型参数括在方括号中,而值参数括在括号中。例子如下:
def listOfDuplicates[A](x: A, length: Int): List[A] = {
if (length < 1)
Nil
else
x :: listOfDuplicates(x, length - 1)
}
println(listOfDuplicates[Int](3, 4))
println(listOfDuplicates("La", 8))
结果如下:
该方法listOfDuplicates
采用类型参数A
和值参数x
和length
。价值x
是类型A
。如果length < 1
返回一个空列表。否则,前缀x
到递归调用返回的重复列表。(注意,这::
意味着将左侧的元素添加到右侧的列表中。)
例1中,通过写入显式提供了类型参数[Int]
。因此,第一个参数必须是a Int
,返回类型将是List[Int]
。
例2显示您并不总是需要显式提供type参数。编译器通常可以根据上下文或值参数的类型来推断它。在这个例子中,"La"
是一String
所以编译器知道A
必须String
。
4、类型推断
Scala编译器通常可以推断表达式的类型,因此您不必显式声明它。
- 省略类型
val businessName = "Café"
编译器可以检测到它businessName
是一个String。它与方法类似:
def squareOf(x: Int) = x * x
编译器可以推断返回类型是 Int
,因此不需要显式返回类型。
编译器无法对递归方法推断结果类型。这是一个程序,由于这个原因将使编译器失败:
def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)
在调用多态方法或实例化泛型类时,也不必强制指定类型参数。Scala编译器将从上下文和实际方法/构造函数参数的类型推断出这样的缺失类型参数。
这是两个例子:
case class MyPair[A, B](x: A, y: B);
val p = MyPair(1, "scala") //多态方法 def id[T](x: T) = x
val q = id(1) //泛型类
编译器使用参数的类型MyPair
来确定哪种类型A
和类型B
。同样的类型x
。
- 参数
编译器永远不会推断出方法参数类型。但是,在某些情况下,当函数作为参数传递时,它可以推断出匿名函数参数类型。
Seq(1, 3, 4).map(x => x * 2)
map的参数是f: A => B
。因为我们把整数放在中Seq
,所以编译器知道那A
是Int
(即它x
是一个整数)。因此,编译器可以推断从x * 2
该B
是类型Int
。
- 不依赖类型推断
通常认为声明在公共API中公开的成员类型更具可读性。因此,我们建议您为将向您的代码用户公开的任何API明确指定类型。
此外,类型推断有时可以推断出太具体的类型。假设我们写道:
var obj = null
我们不能继续进行这种重新分配:
obj = new AnyRef
它不会编译,因为推断的类型obj
是Null
。由于该类型的唯一值是null
,因此无法分配不同的值。
Scala实践13的更多相关文章
- 【原创 Hadoop&Spark 动手实践 13】Spark综合案例:简易电影推荐系统
[原创 Hadoop&Spark 动手实践 13]Spark综合案例:简易电影推荐系统
- Scala实践6
1 if表达式 Scala中if...else..表达式是有返回值的,如果if和else返回值类型不一样,则返回Any类型. scala> val a3=10 a3: Int = 10 sca ...
- Scala实践5
一.Scala的层级 1.1类层级 Scala中,Any是所其他类的超类,在底端定义了一些有趣的类NULL和Nothing,是所有其他类的子类. 根类Any有两个子类:AnyVal和AnyRef.其中 ...
- Scala实践4
一.数组 在Scala中,用()来访问元素,数组声明的语法格式如下 : var z:Array[String] = new Array[String](3) 或 var z = new Array[S ...
- Scala实践3
一.函数式对象 1.1 rational类的规格和创建 Rational类来源于有理数(rational number),来表示n(分子)/d(分母)的数字,同时对有理数的运算(加减乘除)建模,还具 ...
- Linux IPC实践(13) --System V IPC综合实践
实践:实现一个先进先出的共享内存shmfifo 使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速; 我们首先完成C语言版本的shmfifo(基于过程调用) ...
- es6+最佳入门实践(13)
13.模块化 13.1.什么是模块化 模块化是一种处理复杂系统分解为更好的可管理模块的方式.通俗的讲就是把一个复杂的功能拆分成多个小功能,并且以一种良好的机制管理起来,这样就可以认为是模块化.就像作家 ...
- Scala实践14
1.Scala的future 创建future import scala.concurrent._ import ExecutionContext.Implicits.global object Fu ...
- Scala实践12
1.内部类和抽象类型成员作为对象成员 内部类 在Scala中,可以让类将其他类作为成员.这些内部类是封闭类的成员.在Scala中,这样的内部类绑定到外部对象.假设希望编译器在编译时阻止我们混合哪些节点 ...
随机推荐
- Python--day65--母版和继承的基本使用
- java 集合之HashMap的三种遍历
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射. 这周我们只需记住三种遍历方法 1.通过keySet()获取键,再利用hashmap里面的.get(key)方法通过键获取 ...
- Python--day41--事件和信号量之模拟连接数据库并在连接三次后抛出连接超时异常
#事件被创建的时候#False状态 #wait()阻塞#True状态 #wait() 非阻塞#clear 设置状态为False#set 设置状态为True #数据库 --- 文件夹#文件夹里有好多ex ...
- 【codeforces 789A】Anastasia and pebbles
[题目链接]:http://codeforces.com/contest/789/problem/A [题意] 有n种物品,每种物品有wi个; 你有两个口袋,每个口袋最多装k个物品; 且口袋里面只能装 ...
- linux中添加常用应用程序的桌面图标
在网上随处可以找到怎么样把应用程序的图标放到桌面上,我刚用ubuntu时也是按照网上的做法,一步一步的做的,现将网上的做法复制下来: 桌面配置文件简述\label{sec:desktop file} ...
- HDU 2454"Degree Sequence of Graph G"(度序列可图性判断)
传送门 参考资料: [1]:图论-度序列可图性判断(Havel-Hakimi定理) •题意 给你 n 个非负整数列,判断这个序列是否为可简单图化的: •知识支持 握手定理:在任何无向图中,所有顶点的度 ...
- tf.train.match_filenames_once()
文件匹配之用 官方解释: 调用样例: https://bbs.csdn.net/topics/392271556 返回值样例:
- 【t050】方程求解
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 要求Xi(i = 1,2,3,4)是一个[-T..T]中的整数,满足方程AX1 + BX2 + CX3 ...
- C#面试题整理2(不带答案)
一.C# 理论 1.1.简述 private. protected. public. internal.protected internal 访问修饰符和访问权限 1.2.简述abstract.sea ...
- JMeter录制登录测试
本节试图解释使用任何公开可用的网站记录登录测试的确切步骤,该网站提供具有登录凭据的可靠登录页面. 出于测试目的,我们将使用OrangeHRM在URL- http://opensource.demo.o ...