Scala学习笔记(四)(函数相关)

Scala函数问题:

函数是一组一起执行任务的语句。可以将代码放到独立的功能。如何划分你的代码不同功能?在逻辑上,通常是让每个函数执行特定的任务。


Scala有函数和方法,我们术语说的方法和函数互换用微小的差别。Scala方法是其中有一个名字,签名,任选一些注释,有的字节码,

其中如在Scala中函数是可被分配给一个变量的完整对象类的一部分。换句话说,函数,其被定义为某些对象的一个成员,被称为方法。


函数定义可以出现在在源文件的任何地方,Scala允许嵌套函数的定义,那就是其他函数定义的内部函数定义。需要注意的最重要的一点是,

Scala的函数名称可以类似+, ++, ~, &,-, -- , , /, : 等字符。


函数定义:


Scala函数定义有如下形式:


def functionName ([list of parameters]) : [return type] = {
   function body
   return [expr]
}

在这里,返回类型可以是任何有效的scala数据类型,参数列表将是用逗号和参数,返回值类型列表分离变量是可选的。非常类似于Java,一个返回语句可以在函数表达式可用情况下返回一个值。以下是这将增加两个整数并返回的函数:


object add{
   def addInt( a:Int, b:Int ) : Int = {
      var sum:Int = 0
      sum = a + b

      return sum
   }
}

函数,它不返回任何东西,可以返回这相当于在Java中void,并表示该函数不返回任何单元。Scala中不返回任何东西函数被称为过程。以下是语法


object Hello{
   def printMe( ) : Unit = {
      println("Hello, Scala!")
   }
}

调用函数:


Scala提供了一些语法的变化来调用方法。以下是调用一个方法的标准方法:


如果函数被对象的一个实例调用使用,那么使用类似于Java点标记如下:


[instance.]functionName( list of parameters )

下面是一个例子用来定义,然后调用函数:


 


 


object Test {
   def main(args: Array[String]) {
        println( "Returned Value : " + addInt(5,7) );
   }
   def addInt( a:Int, b:Int ) : Int = {
      var sum:Int = 0
      sum = a + b

      return sum
   }
}

让我们编译和运行上面的程序,这将产生以下结果:


C:/>scalac Test.scala
C:/>scala Test
Returned Value : 12

C:/>

Scala函数是Scala编程的核心,这就是为什么Scala被假定为一个函数式编程语言.


Scala函数按名称调用

通常情况下,函数的参数是传值参数;即,参数的值在它被传递给函数之前被确定。但是,如果我们需要编写一个接收参数不希望马上计算,直到调用函数内的表达式。对于这种情况,Scala提供按名称参数调用函数。

按名称调用机制传递一个代码块给被调用者并且每次被调用方传接入参数,代码块被执行,值被计算。

object Test {
   def main(args: Array[String]) {
        delayed(time());
   }

   def time() = {
      println("Getting time in nano seconds")
      System.nanoTime
   }
   def delayed( t: => Long ) = {
      println("In delayed method")
      println("Param: " + t)
      t
   }
}

在这里,我们声明delayed方法,它通过=>符号变量的名称和类型,需要一个按名称调用参数。当上述代码被编译和执行时,它产生了以下结果:


C:/>scalac Test.scala
C:/>scala Test
In delayed method
Getting time in nano seconds
Param: 81303808765843
Getting time in nano seconds
这里,delayed打印的消息声明,该方法已被输入。接下来,delayed打印一个与其消息的值。最后delayed方法返回 t。

Scala函数使用命名参数

在一个正常的函数调用,调用参数在调用函数的参数的顺序一一匹配。命名参数允许将参数以不同的顺序传递给的函数。语法很简单,每个参数前面有一个参数名和等号。下面是一个简单的例子来说明这一概念:

object Test {
   def main(args: Array[String]) {
        printInt(b=5, a=7);
   }
   def printInt( a:Int, b:Int ) = {
      println("Value of a : " + a );
      println("Value of b : " + b );
   }
}

当上述代码被编译和执行时,它产生了以下结果:


C:/>scalac Test.scala
C:/>scala Test
Value of a :  7
Value of b :  5

 

Scala函数使用可变参数


Scala允许指出的最后一个参数的函数可以被重复。能够通过可变长度参数列表传递到函数。下面是一个简单的例子来说明这个概念。


object Test {
   def main(args: Array[String]) {
        printStrings("Hello", "Scala", "Python");
   }
   def printStrings( args:String* ) = {
      var i : Int = 0;
      for( arg <- args ){
         println("Arg value[" + i + "] = " + arg );
         i = i + 1;
      }
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Arg value[0] = Hello
Arg value[1] = Scala
Arg value[2] = Python

 在这里,printStrings函数,这被声明为类型为“String*”里的args类型实际上是数组[字符串]。


Scala函数默认参数值


Scala可以指定默认值函数的参数。对于这样的一个参数,可以任选地从一个函数调用,在这种情况下对应的参数将被填充使用默认参数值。下面是指定默认参数的一个例子:


object Test {
   def main(args: Array[String]) {
        println( "Returned Value : " + addInt() );
   }
   def addInt( a:Int=5, b:Int=7 ) : Int = {
      var sum:Int = 0
      sum = a + b

      return sum
   }
}

当上述代码被编译和执行时,它产生了以下结果:


C:/>scalac Test.scala
C:/>scala Test
Returned Value : 12
 

Scala高阶函数

Scala允许高阶函数的定义。这些都是采取其他函数参数,或它的结果是一个功能的函数。例如在下面的代码,适用于apply()函数将另一个函数f和v值并应用函数f到v:

object Test {
   def main(args: Array[String]) {

      println( apply( layout, 10) )

   }

   def apply(f: Int => String, v: Int) = f(v)

   def layout[A](x: A) = "[" + x.toString() + "]"

}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
[10]

 

Scala匿名函数

Scala中提供相对轻便的语法定义匿名函数。在源代码中的匿名函数被调用函数文本,并在运行时,函数文本被实例化为调用的函数值的对象。

Scala支持一流的功能,这意味着可以表达功能文本语法功能,即,(x: Int) => x + 1,函数都可以通过对象,这是所谓的函数值来表示。下面的表达式创建一个后继函数的整数:

var inc = (x:Int) => x+1

变量inc现在可以使用以通常的方式的函数:

var x = inc(7)-1

另外,也可以用多个参数定义的函数如下:

var mul = (x: Int, y: Int) => x*y

变量mul现在可以使用以通常的方式的函数:

println(mul(3, 4))

另外,也可以用无参数定义函数如下:

var userDir = () => { System.getProperty("user.dir") }

变量userDir现在可以使用以通常的方式的函数:

println( userDir )

Scala柯里函数

柯里转换函数接受多个参数成一条链的函数,每次取一个参数。柯里函数是具有多个参数列表定义,如下:

def strcat(s1: String)(s2: String) = s1 + s2

另外,还可以使用以下语法定义柯里函数:

def strcat(s1: String) = (s2: String) => s1 + s2

以下是语法来调用一个柯里函数:

strcat("foo")("bar")

可以根据柯里函数需求定义两个以上的参数。让我们以一个完整的例子来说明柯里的概念:

object Test {
   def main(args: Array[String]) {
      val str1:String = "Hello, "
      val str2:String = "Scala!"
      println( "str1 + str2 = " +  strcat(str1)(str2) )
   }

   def strcat(s1: String)(s2: String) = {
      s1 + s2
   }
}

当上述代码被编译和执行时,它产生了以下结果:
C:/>scalac Test.scala
C:/>scala Test
str1 + str2 = Hello, Scala!

Scala嵌套函数

Scala允许在一个函数内部定义其他函数定义的函数,并可被局部函数调用。这里是一个阶乘计算器,在这里使用调用第二个函数,嵌套方式是传统技术的一个实现:

object Test {
   def main(args: Array[String]) {
      println( factorial(0) )
      println( factorial(1) )
      println( factorial(2) )
      println( factorial(3) )
   }

   def factorial(i: Int): Int = {
      def fact(i: Int, accumulator: Int): Int = {
         if (i <= 1)
            accumulator
         else
            fact(i - 1, i * accumulator)
      }
      fact(i, 1)
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
1
1
2
6

C:/>

像在许多语言中的局部变量声明,嵌套方法只封闭方法内可见。如果试图调用 fact() 在factorial()之外,将会得到一个编译器错误。

Scala部分应用函数

当调用函数,可以认为是将参数传给函数。通过所有希望的参数并完全把它传到应用。如果只发送了几个参数,会得到一个部分函数应用。也可以绑定一些参数,剩下其余的稍后再填补上。下面是一个简单的例子来说明这一概念:

import java.util.Date

object Test {
   def main(args: Array[String]) {
      val date = new Date
      log(date, "message1" )
      Thread.sleep(1000)
      log(date, "message2" )
      Thread.sleep(1000)
      log(date, "message3" )
   }

   def log(date: Date, message: String)  = {
     println(date + "----" + message)
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Mon Dec 02 12:52:41 CST 2013----message1
Mon Dec 02 12:52:41 CST 2013----message2
Mon Dec 02 12:52:41 CST 2013----message3

C:/>

在这里,log()方法有两个参数:date和message。如果想多次调用这个方法,如:date 使用不同的值,而 message 的值相同。我们可以消除部分参数传递给 log() 方法,因为传递 date 在每个调用都可能会有干扰。要做到这一点,我们首先绑定一个值到 date 参数,并把下划线放在其位置第二个参数之后。现在我们已经存储一个变量的部分应用到函数。可以与未结合的 mesage 参数调用这个新方法如下:

import java.util.Date

object Test {
   def main(args: Array[String]) {
      val date = new Date
      val logWithDateBound = log(date, _ : String)

      logWithDateBound("message1" )
      Thread.sleep(1000)
      logWithDateBound("message2" )
      Thread.sleep(1000)
      logWithDateBound("message3" )
   }

   def log(date: Date, message: String)  = {
     println(date + "----" + message)
   }
}

当上述代码被编译和执行时,它产生了以下结果:

C:/>scalac Test.scala
C:/>scala Test
Mon Dec 02 12:53:56 CST 2013----message1
Mon Dec 02 12:53:56 CST 2013----message2
Mon Dec 02 12:53:56 CST 2013----message3

C:/>

Scala闭包

闭包是函数,它的返回值取决于此函数之外声明一个或多个变量的值。考虑下面的一块使用匿名函数的代码:

val multiplier = (i:Int) => i * 10

在这里,在函数体中使用的唯一变量, i * 0, 为i,其被定义为一个参数的函数。现在,让我们来看另一块代码:

val multiplier = (i:Int) => i * factor

有两个自由变量的乘数:i和factor。其中一个i是一个正式函数参数。因此,它被绑定到一个新的值在乘数每次调用。然而,factor不是一个正式的参数,那么这是什么?让我们增加一行代码:

var factor = 3
val multiplier = (i:Int) => i * factor

现在,factor具有参考变量在函数之外,但为封闭范围的变量。让我们试试下面的例子:

object Test {
   def main(args: Array[String]) {
      println( "muliplier(1) value = " +  multiplier(1) )
      println( "muliplier(2) value = " +  multiplier(2) )
   }
   var factor = 3
   val multiplier = (i:Int) => i * factor
}
让我们编译和运行上面的程序,这将产生以下结果:
C:/>scalac Test.scala
C:/>scala Test
muliplier(1) value = 3
muliplier(2) value = 6
上面的函数引用factor并读取每个时间的当前值。如果函数没有外部引用,那么它就是封闭了自己。无需外部环境是必需的。
 
时间: 2024-08-17 17:39:07

Scala学习笔记(四)(函数相关)的相关文章

Caliburn.Micro学习笔记(四)----IHandle&lt;T&gt;实现多语言功能

Caliburn.Micro学习笔记(四)----IHandle<T>实现多语言功能 说一下IHandle<T>实现多语言功能 因为Caliburn.Micro是基于MvvM的UI与codebehind分离, binding可以是双向的所以我们想动态的实现多语言切换很是方便今天我做一个小demo给大家提供一个思路 先看一下效果 点击英文  变成英文状态点chinese就会变成中文                          源码的下载地址在文章的最下边 多语言用的是资源文件建

Scala学习笔记及与Java不同之处总结-从Java开发者角度

Scala与Java具有很多相似之处,但又有很多不同.这里主要从一个Java开发者的角度,总结在使用Scala的过程中所面临的一些思维转变. 这里仅仅是总结了部分两种语言在开发过程中的不同,以后会陆续更新一些切换后在开发过程中值得注意的地方.以下列举了部分,但令人印象深刻的Scala语言的不同之处,具体的代码演示样例及具体阐述见下文. ? Scala中可直接调用Java代码,与Java无缝连接. 语句能够不用";"结束.且推荐不适用";". 变量声明时以var或va

代码管理工具 --- git的学习笔记四《重新整理git(1)》

1.创建版本库 mkdir  创建目录 cd  地址,到该地址下 pwd 显示当前目录 1.创建目录 $ mkdir startGit $ cd startGit $ pwd 显示当前目录 或者cd到桌面,然后再创建目录 2.初始化版本库 $ git init 初始化仓库 提示信息:Initialized empty Git repository in /Users/xingzai/Desktop/startGit/.git/ 建立一个空的git仓库在/Users/xingzai/Desktop

Linux学习笔记四:Linux的文件搜索命令

1.文件搜索命令  which 语法:which [命令名称] 范例:$which ls  列出ls命令所在目录 [[email protected] ~]$ which ls alias ls='ls --color=auto' /bin/ls 另外一个命令:whereis [名称名称],也可以列出命令所在目录. [[email protected] ~]$ whereis ls ls: /bin/ls /usr/share/man/man1/ls.1.gz /usr/share/man/ma

小猪的数据结构学习笔记(四)

小猪的数据结构学习笔记(四) 线性表之静态链表 --转载请注明出处:coder-pig 本章引言: 在二,三中中我们分别学习了顺序表中的线性表与单链表,线性表有点类似于 我们前面所学的数组,而单链表使用的最多的是指针,这里问个简单的问题, 如果是在以前没有指针的话,前辈先人们怎么实现单链表呢?大家思考下! 没有指针,那么用什么来代替呢?前辈先人们非常机智,想出了使用下标+游标的方式 来实现单链表的效果!也就是今天要讲的--静态链表! 当然你也可以直接跳过本章,因为有了单链表就没有必要用静态链表了

Swift学习笔记四:数组和字典

最近一个月都在专心做unity3d的斗地主游戏,从早到晚,最后总算是搞出来了,其中的心酸只有自己知道.最近才有功夫闲下来,还是学习学习之前的老本行--asp.net,现在用.net做项目流行MVC,而不是之前的三层,既然技术在更新,只能不断学习,以适应新的技术潮流! 创建MVC工程 1.打开Visual studio2012,新建MVC4工程 2.选择工程属性,创建MVC工程 3.生成工程的目录 App_Start:启动文件的配置信息,包括很重要的RouteConfig路由注册信息 Conten

NLTK学习笔记(四):自然语言处理的一些算法研究

自然语言处理中算法设计有两大部分:分而治之 和 转化 思想.一个是将大问题简化为小问题,另一个是将问题抽象化,向向已知转化.前者的例子:归并排序:后者的例子:判断相邻元素是否相同(与排序). 这次总结的自然语言中常用的一些基本算法,算是入个门了. 递归 使用递归速度上会受影响,但是便于理解算法深层嵌套对象.而一些函数式编程语言会将尾递归优化为迭代. 如果要计算n个词有多少种组合方式?按照阶乘定义:n! = n*(n-1)*...*1 def func(wordlist): length = le

Android学习笔记四:添加Source

问题描述 Source not foundThe JAR file D:\.....\sdk\platforms\android-20\android.jar has no source attachment. 问题原因及解决办法 1. 使用SDK Manager下载最新版本的Sources for Android SDK 一般文件下载目录默认在SDK下的sources文件中即 \adt-bundle-windows-x86_64-20130522\sdk\sources\android-20

【Unity 3D】学习笔记四十二:粒子特效

粒子特效 粒子特效的原理是将若干粒子无规则的组合在一起,来模拟火焰,爆炸,水滴,雾气等效果.要使用粒子特效首先要创建,在hierarchy视图中点击create--particle system即可 粒子发射器 粒子发射器是用于设定粒子的发射属性,比如说粒子的大小,数量和速度等.在创建完粒子对象后,在右侧inspector视图中便可以看到所有的粒子属性: emit:是否是使用粒子发射器. min size:粒子最小尺寸. max size:粒子最大尺寸. min energy:粒子的最小生命周期