首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用Scala实现一个简单的Python的上下文管理器

用Scala实现一个简单的Python的上下文管理器

作者头像
哒呵呵
发布2018-08-06 14:14:49
6040
发布2018-08-06 14:14:49
举报
文章被收录于专栏:鸿的学习笔记鸿的学习笔记

上下文管理器是对try/finally模式的简化,保证一段代码运行完后执行某项操作,即使那段代码被中止了,也会执行指定的操作。在这篇文章将展现函数式编程的威力,用Scala写一个简单的上下文管理器。

简单介绍下Python的with,它是属于上下文管理器协议,使用__enter__和__exit__方法实现协议,在with语句运行之前会调用__enter__方法,结束之后调用__exit__方法。最常见的例子就是关闭文件对象,这次我们也要用Scala实现下面的语法。

with open('D:\\data.txt') as f:
    data = f.read()

f.closed
Out[3]: True

在开始写之前,先了解下柯里化(Currying)的概念。柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数。先看看一个正常的oldSum函数:

scala> def oldSum(x:Int, y:Int) = x + y
oldSum: (x: Int, y: Int)Int

scala> oldSum(1,2)
res0: Int = 3

scala> def curriedSum(x:Int)(y:Int) = x + y
curriedSum: (x: Int)(y: Int)Int

scala> curriedSum(1)(2)
res1: Int = 3

curriedSum是柯里化函数,当在调用curriedSum时,实际上是连着做了两次的函数调用,可以理解为是一个嵌套函数:

scala> def first(x:Int) = (y:Int) => x + y
first: (x: Int)Int => Int

scala> val second = first(1)
second: Int => Int = <function1>

scala> second(2)
res3: Int = 3

虽然实现原理并不一致,但是可以这么理解柯里化的实现过程,并且也可以通过占位符(一个神奇的符号)去缓存第二个函数的使用。

scala> val onePlus = curriedSum(1)_
onePlus: Int => Int = <function1>

scala> onePlus(2)
res4: Int = 3

当了解柯里化后,回忆一下,前文提到了Scala里的函数是一等对象,函数本身是可以当作参数传给函数的:

scala> def twicePlus(plus:Int => Int, x:Int) = plus(plus(x))
twicePlus: (plus: Int => Int, x: Int)Int

scala> twicePlus(_+1,5)
res5: Int = 7

神奇的_符号又来了,_ + 1可以理解为(如果不是老手,_+1并没有下面的容易理解):

scala> val add=(x:Int) => x+ 1
add: Int => Int = <function1>

scala> twicePlus(add,5)
res6: Int = 7

plus:Int => Int,这里的含义是传入一个入参为Int类型的值,返回值是Int类型值函数。除了圆括号,函数的参数传入也能使用{},例如:

scala> println("hello,world")
hello,world

scala> println {"hello,world"}
hello,world

Scala在函数的入参只有一个函数时,允许你使用{}调用函数,不过仅限你的函数只接受一个入参。有了这个铺垫,下面的withFile就容易理解了。withFile是一个柯里化函数,第二个参数列表需要传入一个输入类型为BufferedSource,无返回值的函数,我们借用了{}去模仿Scala的控制结构。一个简单的上下文管理器就实现了。

object withControl{
  def main(args: Array[String]): Unit = {
    val file = Source.fromFile("D:\\data.txt")
    withFile(file) {
      writer => println(writer.length)
    }
  }

  def withFile(file: BufferedSource)(op:  BufferedSource => Unit) = {
    try{
      op(file)
    }
    finally {
      file.close()
    }
  }
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 鸿的学习笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档