Scala教程之:静态类型(三)

简介: Scala教程之:静态类型(三)

自类型


自类型的意思是在一个trait中可以使用另外一个trait中定义的属性而不必去继承它。


要在特质中使用自类型,写一个标识符,跟上要混入的另一个特质,以及 =>(例如 someIdentifier: SomeOtherTrait =>)。


trait User {
  def username: String
}
trait Tweeter {
  this: User =>  // 重新赋予 this 的类型
  def tweet(tweetText: String) = println(s"$username: $tweetText")
}
class VerifiedTweeter(val username_ : String) extends Tweeter with User {  // 我们混入特质 User 因为 Tweeter 需要
  def username = s"real $username_"
}
val realBeyoncé = new VerifiedTweeter("Beyoncé")
realBeyoncé.tweet("Just spilled my glass of lemonade")  // 打印出 "real Beyoncé: Just spilled my glass of lemonade"


因为我们在特质 trait Tweeter 中定义了 this: User =>,现在变量 username 可以在 tweet 方法内使用。 这也意味着,由于 VerifiedTweeter 继承了 Tweeter,它还必须混入 User(使用 with User)。


隐式参数


隐式参数由 implicit 关键字标记,在方法调用的时候,scala会去尝试获取正确的隐式类型值。


Scala查找参数的位置有两个地方:


  • 首先查找可以直接访问的隐式定义和隐式参数。
  • 然后,它在所有伴生对象中查找与隐式候选类型相关的有隐式标记的成员。


下面的例子定义了两个隐式类型,stringMonoid和intMonoid。


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)))       // uses IntMonoid implicitly
    println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly
  }
}


在 main 方法中我们调用了 sum 方法两次,并且只传入参数 xs。 Scala 会在上例的上下文范围内寻找隐式值。 第一次调用 sum 方法的时候传入了一个 List[Int] 作为 xs 的值,这意味着此处类型 A 是 Int。 隐式参数列表 m 被省略了,因此 Scala 将查找类型为 Monoid[Int] 的隐式值。


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


第二次调用 sum 方法的时候传入一个 List[String],这意味着此处类型 A 是 String。 与查找 Int 型的隐式参数时类似,但这次会找到 stringMonoid,并自动将其作为 m 传入。


隐式转换


简单点讲,隐式转换就是当需要的时候,将某个类型S转换到另外一个类型T。这是通过定义隐式函数来确定的。


下面提供了一个隐式方法 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
  }


如果需要Ordered[List[A]] 而你传入List[A]的时候,scala会自动去寻找隐式的类型转换方法。


下面是一个从scala.Int到java.lang.Integer的转换:


import scala.language.implicitConversions
implicit def int2Integer(x: Int) =
  java.lang.Integer.valueOf(x)


多态方法


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))  // List(3, 3, 3, 3)
println(listOfDuplicates("La", 8))  // List(La, La, La, La, La, La, La, La)


上例中第一次调用方法时,我们显式地提供了类型参数 [Int]。 因此第一个参数必须是 Int 类型,并且返回类型为 List[Int]。


上例中第二次调用方法,表明并不总是需要显式提供类型参数。 编译器通常可以根据上下文或值参数的类型来推断。 在这个例子中,“La” 是一个 String,因此编译器知道 A 必须是 String。


类型推断


Scala 编译器通常可以推断出表达式的类型,因此你不必显式地声明它。


val businessName = "Montreux Jazz Café"


编译器可以发现 businessName 是 String 类型。


你也可以省略方法返回类型:


def squareOf(x: Int) = x * x


编译器可以推断出方法的返回类型为 Int,因此不需要明确地声明返回类型。


当调用 多态方法 或实例化 泛型类 时,也不必明确指定类型参数。 Scala 编译器将从上下文和实际方法的类型/构造函数参数的类型推断出缺失的类型参数。


看下面两个例子:


case class MyPair[A, B](x: A, y: B)
val p = MyPair(1, "scala") // type: MyPair[Int, String]
def id[T](x: T) = x
val q = id(1)              // type: Int


编译器使用传给 MyPair 参数的类型来推断出 A 和 B 的类型。对于 x 的类型同样如此。

相关文章
|
6月前
|
IDE Java 编译器
scala的两种变量类型 var 和 val
scala的两种变量类型 var 和 val
147 2
scala的两种变量类型 var 和 val
|
安全 Java 大数据
大数据开发基础的编程语言的Scala的类型系统
Scala是一种强类型的编程语言,它具有一套完善的类型系统。本文将介绍Scala的类型系统,帮助开发者了解这门语言的类型安全性和灵活性。
93 0
|
分布式计算 Java Scala
一天学完spark的Scala基础语法教程十三、文件IO操作(idea版本)
一天学完spark的Scala基础语法教程十三、文件IO操作(idea版本)
115 0
一天学完spark的Scala基础语法教程十三、文件IO操作(idea版本)
|
分布式计算 Java Scala
一天学完spark的Scala基础语法教程十二、异常处理(idea版本)
一天学完spark的Scala基础语法教程十二、异常处理(idea版本)
200 0
一天学完spark的Scala基础语法教程十二、异常处理(idea版本)
|
分布式计算 Java Scala
一天学完spark的Scala基础语法教程十一、正则表达式(idea版本)
一天学完spark的Scala基础语法教程十一、正则表达式(idea版本)
157 0
一天学完spark的Scala基础语法教程十一、正则表达式(idea版本)
|
存储 分布式计算 Java
一天学完spark的Scala基础语法教程十、类和对象(idea版本)
一天学完spark的Scala基础语法教程十、类和对象(idea版本)
125 0
一天学完spark的Scala基础语法教程十、类和对象(idea版本)
|
分布式计算 Scala Spark
一天学完spark的Scala基础语法教程九、迭代器(idea版本)
一天学完spark的Scala基础语法教程九、迭代器(idea版本)
131 0
一天学完spark的Scala基础语法教程九、迭代器(idea版本)
|
分布式计算 Scala Spark
一天学完spark的Scala基础语法教程八、集合(idea版本)
一天学完spark的Scala基础语法教程八、集合(idea版本)
143 0
一天学完spark的Scala基础语法教程八、集合(idea版本)
|
存储 分布式计算 Scala
一天学完spark的Scala基础语法教程七、数组(idea版本)
一天学完spark的Scala基础语法教程七、数组(idea版本)
132 0
一天学完spark的Scala基础语法教程七、数组(idea版本)
|
大数据 Java 编译器
Scala 字符类型|学习笔记
快速学习 Scala 字符类型。
174 0