scala基础之五 隐式转换和隐式函数

16 篇文章 0 订阅
5 篇文章 0 订阅

标签(空格分隔): hadoop scala


带着问题去学习

什么是隐式转换,隐式参数?

有什么用?
隐式转换也是一种增强,丰富现有类库功能的一种方式
怎么使用?
隐式转换的触发条件,和非触发条件?

隐式转换

如果是使用过动态代理或者aop,或者装饰着模式 那么应该知道在许多情况下我们可以通过这些方法进行类功能增强。
而隐式转换也是一种增强,丰富现有类库功能的一种方式。

隐式转换函数

隐式转换函数:就是以关键字implict定义的带有单个参数函数。
例如:

implicit def int2Double(x: Int) = x.toDouble

隐式转换函数如它的名字一样,功能就是将类型进行隐式的转换。
通过这种转换我们就可以丰富现有类库的功能。
下面我们用一下scala对应的File增强的例子。
首先是增强类

class RichFile(file: File) {
  def read = Source.fromFile(file.getPath).mkString
}

接着是要使用的对象

object EnhandTestObject{
  def main(args: Array[String]): Unit = {
    val file = new File("D:\\词典\\stopword.dic") //stopword.dic就是一个普通的txt里面有内容
    implicit def file2RichFile(file :File) = new RichFile(file)//在当前作用域中直接引用
    //import com.lcy.hello.impl_enhance.EnHanceFile._//或者引入某个对象中的隐式转换函数,下面就是写的隐式转换对象
    file.read
  }
}

还有一个是包含隐式转换的对象

object EnHanceFile {

   implicit def file2RichFile(file :File) = new RichFile(file)

   implicit def int2Double(x: Int) = x.toDouble
}

这里有两个知识点需要说下:隐式转换流程?引入隐式转换的方式都有几种?

1)怎么转换了需要定义以下哪几个步骤(流程)
a.首先我们需要定义一个增强类 就是上面说的RichFile 人家就是拿到File提供一个read方法,可直接通过read完成文件读取。
b.增强类有了,我们需要引用这个增强类,那么引用的过程我们通过隐式转换,怎么用呢,我们可以直接将隐式转换放在作用域上,比如 EnhandTestObject的main方法中直接通过 implict定义隐式函数即可,接着就可以完成file.read的调用,因为file被隐式转换成了RichFile了。
c.或者我们搞一个object对象 存放隐式转换函数,我们可以通过 import com.lcy.hello.impl_enhance.EnHanceFile._ 的形式去引入这个隐式函数,后面的“_” 不可少 后面再介绍这个引入。

2)隐式转换的使用方式有几种
刚刚1)中说了 我们可以直接在作用域中定义是一种。 第二种是通过一个对象去存放隐式转换函数我们通过import导入进来也可使用。
上面的两种都是在作用域中引入了,另外一种就是如果这个类的伴生对象存在隐式转换也是会被使用的。这个在隐式转换规则我们下面再说。

隐式转换规则(是不是导入隐式转换就一定会转换)

隐式转换也有规则的不是所有的牛奶都叫特仑苏。。。错了 不是所有的隐式转换都能够转换成功。下面说下原则(人家隐式转换也是讲原则的)

比如刚刚的
第一种情况 如果访问file.read成员不存在 file作为调用对象就会被转换成RichFile(前提是有引入隐式转换啊下面不强调),这里是作为调用提供方
new File(“README.md”).read
第二种情况
比如我们定义了一个方法:

  def printlnDou(x: Double) ={
    println("x=" +x)
  }
  
  //然后我们在main方法中这么写
  val x: Int = 1
  printlnDou(x)
  //编译通过,运行通过你敢信 你再去看下会发现Int的伴生对象存在隐式转换函数
  implicit def int2double(x : scala.Int) : scala.Double = { /* compiled code */ }  这个我们不需要引入人家都可以进行隐式转换,Int伴生对象存在隐式函数

所以说明下,如果作为参数使用,而本身不符合类型的话 也会被隐式转换的。
第三种情况
如果这个类木有这个方法,而隐式转换后存在则会被隐式转换,跟第一种我理解起来差不多。

另外还有三种情况编译的时候不会被隐式转换的情况。
1)如果本身就能完成编译不会被隐式转换。这个好理解
2)二义性:如果一个参数会有两种隐式转换情况,这种情况会报错比如 a*b 既可以convert1(a)*b 又可以 convert2(a) b
3)编译器不会进行二次转换 比如 正常a
b 编译器不会进行 convert1(convert2(a))*b

针对2)点,这里说的是针对的是一个对象有两种转换的情况。如果存在
convet1(a) * convert2(b)的情况下,是可以的,而且是 a* convert2(b)会被转换,因为a是属于被调用的对象它不用转换的优先级高。

隐式参数

什么是隐式参数?
隐式参数就是参数上面有implict标识符,强调一下隐式参数在一个括号中只能有一个
怎么用?
隐式参数可以让我们的方法调用变得更简洁,可以可以直接不用传递参数,利用 作用域内的implict的变量,或者引入,或者伴生对象中的参数自动传入。
下面是一个例子:
我们在对象中定义一个包含隐式参数的方法。

  def quote(str:String)(implicit del:Delimiter): Unit ={
    println(del.left + str + del.right)
  }

这个方法调用我们有两种方式,一种是显示调用,一种是通过隐式调用。
比如显示调用:

def main(args: Array[String]): Unit = {
//显示调用
//    quote("我很好")(new Delimiter("<",">"))
}

或者在当前伴生对象中定义一个隐式对象

  implicit val deli = new Delimiter("<",">")
  
  然后通过隐式调用
   def main(args: Array[String]): Unit = {
    quote("我很好")
  }

隐式参数的另一种使用方式,可达成隐式转换

我们用下scala上面的例子加入我想比较两个数据的大小

编译不通过,因为咱们a是否有这个<的方法是没法确定的。
def smaller[T](a: T,b:T) = if(a < b) a else b
我们可以通过Ordered对象完成转换成Ordered对象就可以调用<方法了,而这里我们就可以通过一个隐式参数完成这个操作,其实也就是一个函数完成这个操作只不过这个函数是隐式参数
  def smaller[T](a: T,b:T)(implicit order: T => Ordered[T]) = if(order(a) < b) a else b

之后定义一个隐式函数

  implicit val comFun =  (a :CompareClass) => new Ordered[CompareClass]{
override def compare(that: CompareClass): Int = {
  if(a.a > that.a){
     1
  }else if(a.a < that.a) -1 else 0
}

    override def <(that: CompareClass): Boolean = {
      if(a.a < that.a) true else false
    }
  }
  //main方法调用
  def main(args: Array[String]): Unit = {
    val a =  new CompareClass(1);
    val b =  new CompareClass(2);
    println(smaller(a,b))
  }

这里会有隐式转换将会吧CompareClass转换成Ordered对象这样就可以完成比较了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值