Scala03

Trait基础

scala 中的Trait和Java中的接口(interface)极其类似

接口是彻底的抽象类,所以在Trait中方法是抽象方法(abstract)不给出具体的方法体。在Java中实现接口使用implement 关键字,但是在Scala中无论是继承类还是实现接口都是使用extends关键字

在scala中类继承Trait,必须是实现其中的抽象方法,实现时不需要使用override关键字,同时Scala同Java一样,不支持多继承类,但是支持多继承接口,使用with关键字

package trait_
/**
  * @Author: mio
  * @Date: 2019/10/11 9:22
  */
object Main {
  def main(args: Array[String]): Unit = {
    val otogibaraEra = new Otogibara("Era")
    otogibaraEra.say()
    otogibaraEra.sayByAlice()
    otogibaraEra.sayByMeiji()
    otogibaraEra.sing()
  }
}

class Otogibara(name: String) extends Meiji with Alice {
  def say() = {
    println(s"$name say hello")
  }

  override def sing(): Unit = {
    println(s"$name singing song")
  }
}

trait Meiji {
  def sayByMeiji() = {
    println("Meiji say hello")
  }

}

trait Alice {
  def sayByAlice() = {
    println("Alice say hello")
  }

  // 有点像java的接口,需要子类自己去实现
  def sing()
}

样例类

object Main {
  def main(args: Array[String]): Unit = {
    val gibara = new Vtuber("Otogibara Era", 14)
    val meiji = new Vtuber("Otogibara Era", 14)
    //    是false毫无疑问,但是如果类加上case关键字就会变成true
    println(gibara.equals(meiji))
    println(gibara == meiji)
  }
}

case class Vtuber(name: String, age: Int) {

}

隐式转换

package implicit_

import java.util

/**
  * 场景:别人写的类,不想去改他的源码,然后添加一些属于自己的方法
  *
  * @Author: mio
  * @Date: 2019/10/11 11:13
  */
object Main {
  def main(args: Array[String]): Unit = {
    val linkedList = new util.LinkedList[Int]()
    linkedList.add(1)
    linkedList.add(2)
    linkedList.add(3)
    //    linkedList.forEach()

    //    def foreach[T](linkedList: util.LinkedList[T], f: (T) => Unit) = {
    //      val iter = linkedList.iterator()
    //      while (iter.hasNext) f(iter.next())
    //    }
    //
    //    foreach(linkedList, println)

    //    println("-----")
    //    val vtuber = new otoGibara[Int](linkedList)
    //    vtuber.foreach(println)

    println("----- 隐式转换 -----")
    implicit def minatoaqua[T](linkedList: util.LinkedList[T]): otoGibara[T] = {
      new otoGibara(linkedList)
    }

    linkedList.foreach(println)
  }
}

class otoGibara[T](linkedList: util.LinkedList[T]) {
  def foreach(f: (T) => Unit): Unit = {
    val iter = linkedList.iterator()
    while (iter.hasNext) f(iter.next())
  }
}

官网资料

一个从类型 S 到类型 T 的隐式转换由一个函数类型 S => T 的隐式值来定义,或者由一个可转换成所需值的隐式方法来定义。

隐式转换在两种情况下会用到:

  • 如果一个表达式 e 的类型为 S, 并且类型 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)

scala.Predef.intWrapper 已经自动提供了一个隐式方法 Int => Ordered[Int]。下面提供了一个隐式方法 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

在编译器应用隐式转换时不会发出警告。