scala成长之路(6)函数入门
众所周知,scala作为一门极客型的函数式编程语言,支持的特性包括:
- 函数拥有“一等公民”身份;
- 支持匿名函数(函数字面量)
- 支持高阶函数
- 支持闭包
- 部分应用函数
- 柯里化
首先需要指出,在scala中有方法和函数对象两种形态,方法即是通过def关键字定义的函数,而函数对象则是通过将方法转换而来,或lambda赋值而来。
1. 从“一等公民”说起
很多稍微了解过函数式编程的人可能都听说过“一等公民”这种说法,但却很少有人能明明白白地说出究竟什么是“一等公民”。这里我做个类比你马上就明白了:现实中,什么样的人能被当做一等公民?首先,他必须是个独立的个体——依赖父母或朋友才能生存的人肯定不能被当做公民,更不用说一等了;其次,这个人必须拥有足够的自由——既能上九天揽月,又可下五洋捉鳖,方才能是一等公民。对应到我们的函数式编程,我们可以总结出几个点:
(1) 函数的定义和调用不依赖其他结构,例如C、python、js、scala,而反面典型就是java,因为java的任何函数(方法)都必须定义在类、接口、枚举(其实也是类)中,而且任何的方法调用都要通过对象、类的静态方法或接口(jdk 1.8),方法不可能直接调用,必须依附于其他结构而存在。所以这种情况下函数肯定不是“一等公民”。
(2)函数可以作为函数的参数、返回值,并可以对函数进行变量赋值,而且函数的定义位置极度自由,任何代码块里又能定义函数。
现在我们再来看scala,它完美地契合上边所有的需求(但是注意,除了脚本形式的scala之外,其他的scala程序也只能包含在class或object中),scala中函数支持在函数内部定义,而且使用lambda表达式定义的函数可以赋值给任何变量、常量,所有函数均可作为返回值、参数。
2. lambda表达式的学问
很多scala初学者都倒在了scala的lambda上,因为scala lambda的灵活多样,导致很多时候你可能都看不懂。下面我们从最基本的讲起:
最基本的:
val fun = (a:Int) => {a < 100 && a > 0}
当r定义的参数为函数时:
def fun1(f:String => Unit) = f("wangyalou")
我们可以方便地使用lambda传入需要的函数:
fun1((s:String)=>{println(s)})
注意了,一般人都不这么写,因为作为参数的lambda可~以~简~写~~~~~准备好我要开始啰!首先,省略掉可以推断出来的类型参数:
fun1((s)=>{println(s)})
当只有一个参数时,=>前的()可省:
fun1(s=>{println(s)})
还可再简化,scala中可以用_代替只出现一次的参数:
fun1(println(_)) 或 fun1(println _)
最后,我们甚至连下划线都可以不要了:
fun1(println)
注意,最后的情况我们是利用了编译器支持lambda的“eta转换”,即在表达式只有一个参数,且整个执行部分就是一个函数调用时,可以直接写函数名
插一句:eta扩展(eta-expression)是另一个东西,指的是将一个普通方法转换为函数对象的过程:
val b= too(_,_,_)
val b= too _ //这也可以?是的
val b : (Int,Int,Int) =>Int = foo
其中too为一个参数为3个Int的方法
但是,too(_,_,1)一定不是eta扩展!
下划线的用法博大精深,这里再给出一些例子:
例1:lambda作为参数,_可代替只用一次的参数,且省掉“=>”
val nums = Array(1,2,3,4)
nums.filter(_>2)
运行结果:
res31: Array[Int] = Array(3, 4)
例2:lambda作为参数,_可代替只用一次的参数,且省掉“=>”
scala> def foo(f:(Int,Int)=>Int)(a:Int,b:Int) = f(a,b)
foo: (f: (Int, Int) => Int)(a: Int, b: Int)Int
scala> foo(_+_)(3,4)
res33: Int = 7
例3:lambda作为函数定义,_可代替只用一次的参数,且省掉“=>”,但这时要加上类型,因为这里无法推断出“_”的类型
val b = (_:Int) + (_:Int)
b(1,2)
运行结果:
res32: Int = 3
3. 部分应用函数(偏函数)
一个例子足以说清楚:
scala> def foo(a:Int, b:Int, c:Boolean) = if(c) a+b else a-b
foo: (a: Int, b: Int, c: Boolean)Int
scala> val foom = foo(_:Int,_:Int,false)
foom: (Int, Int) => Int = <function2>
类似于python中的偏函数,这里将某个参数确定,其他参数用"_"代替并指明其类型,注意一定要指明类型啊!!!不然就成了eta扩展失败的案例了!!
scala成长之路(6)函数入门的更多相关文章
- scala成长之路(7)函数进阶——可能是史上最浅显易懂的闭包教程
由于scala中函数内部能定义函数,且函数能作为函数的返回值,那么问题来了,当返回的函数使用了外层函数的局部变量时,会发生什么呢?没错,就产生是闭包. 关于闭包的解释网上一大堆,但基本上都是照葫芦画瓢 ...
- python成长之路七-函数的进阶
1,python中,名称空间分三种: 全局命名空间 局部命名空间(临时命名空间) 内置名称空间 2,作用域(两种): 1,全局作用域 包含:全局名称空间 内置名称空间 2,局部作用域 包含:局 ...
- scala成长之路(5)问题记录
还是在看scala sdk源码的时候,有很多问题要考自己慢慢摸索,这里做个记录. 一. 隐式转换的作用域? 隐式转换需要三个因素 1. 己方(当前对象) 2. 转换函数 3. 对方(转换的目标类) 这 ...
- scala成长之路(4)compaion object——伴生对象的使用
虽然java一直声称自己是完全面向对象的语言,但一直以来都被很多人所质疑,其中java的静态成员函数就是主要的“罪魁祸首”.由于java中保留了静态方法的调用,导致其编程模式依然有过程式编程的可能,尤 ...
- scala成长之路(3)隐式转换
不废话,先上例子:定义一个参数类型为String的函数: scala> def sayHello(name:String) = println("hello " + name ...
- scala成长之路(2)对象和类
scala提供了一种特殊的定义单例的方法:object关键字 scala> object Shabi{ | val age = 0 | val name = "shabi" ...
- scala成长之路(1)基本语法和数据类型
scala作为JVM上的Lisp,是一种geek类型的编程语言,也一直是我等java程序员眼中的梦寐以求的一门技能,遂下定决心花一段时间好好学习scala.第一天学习,主要介绍与java在编程上的主要 ...
- python成长之路六-函数的初识
定义函数 我们现学已知的python函数有<内置函数> 而我们现在要学的是<自定义函数> 1,def 定义一个函数 def name(): # 后接函数名 冒号 pass 2 ...
- 物联网架构成长之路(13)-SpringBoot入门
1. 前言 下载最新版的JavaEE eclipse-jee-oxygen-2-win32-x86_64.zip 安装STS插件 Window->Eclipse Marketplace -> ...
随机推荐
- Android使用Fragment来实现TabHost的功能
http://www.cnblogs.com/tiantianbyconan/p/3360938.html 好了,到此为止,我们已经用Fragment实现了类似TabHost的功能了,下面来看下各个F ...
- 关于String s = new String("xyz");创建了几个字符串对象?的问题
引用自这位朋友:http://blog.sina.com.cn/s/blog_6a6b14100100zn6r.html 首先让我们了解几个概念: 栈:由JVM分配区域,用于保存线程执行的动作和数据引 ...
- Liunx网络管理
本地yum源 yum(Yellow dog Updater, Modified)是一个在 Fedora 和 RedHat 以及CentOS 中的 Shell 前端软件包管理器.基于 RPM 包管理,能 ...
- 把IDENTITY_INSERT 设置为 ON ,还不能插入数据问题
IDENTITY_INSERT 为 ON 时 , 必须把需要插入的列名列出来 不然报错 正确例子: SET IDENTITY_INSERT table(表名) ONinsert into table ...
- css随笔
1. 关于使用pre标签,且要自动换行 可以使用: word-wrap: break-word; white-space: pre-wrap; 2. 更改placeholder样式 .input::- ...
- March 24 2017 Week 12 Friday
Our lives are brief, that is why it's important to search for meaning. 人生短暂,所以才要寻找它的意义. What can we ...
- Thread control block & thread
https://en.wikipedia.org/wiki/Thread_control_block Thread Control Block (TCB) is a data structure in ...
- mxnet数据操作
# coding: utf-8 # In[2]: from mxnet import nd # In[3]: x = nd.arange(12) x # In[4]: x.shape,x.size # ...
- Java从入门到放弃——01.Java 环境搭建
本文目标: 下载与安装JDK 配置Java环境 1.JDK9下载: 下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jav ...
- hyper-net、ion、skip connection、fpn
resnet的skip connection用的也是eltwise相加 fpn的浅层和高层融合用的eltwise相加 hyper-net和ion都是使用的concat的方式 hyper-net网络结构 ...