scala中的函数和方法

一:scala中的函数

Scala中,函数上升和变量同等的位置,或者说函数也是一种变量;

Scala中的函数可以作为实参传递给另一个函数;

函数可以作为返回值;

函数可以赋值给变量(这个变量需符合函数的类型的变量);

函数可以存储在数据结构之中。

函数如同普通变量一样,也具有类型;

 

函数的定义可以有很多种,因此需要掌握最基本的定义方法:

1,函数的基本定义

val f1 = (a: Int, b: Int) => a + b
val f2 = ((a: Int, b: Int) => a + b)
val f3 = (_: Int) + (_: Int)
val f7 = ()
val f4: (Int, Int) => Int = (_ + _)
val f5:(Int,Int)=>Int =(x,y)=>x+y
val f6:(Int,Int)=>Int=(m,n)=>if (m+n>0) m else n

2,自定义函数

scala> val f1 = new Function2[Int, Int, Int] {
     |    def apply(x: Int, y: Int): Int = if (x < y) y else x
     | }
f1: (Int, Int) => Int = <function2>

3,匿名函数

            没有名称的函数是匿名函数,也称为函数文字,或者函数字面量

定义格式:
(形参列表) => {函数体}
例如: (x: Int, y: Int) => x + y

二:scala中的方法

方法的定义:

def max(x:Int,y:Int):Int={
if(x>y)
x
else
y
}

def:开始函数定义

max:函数名

() 括号中的参数列表 (一般称之为入参)

Int: 函数返回值类型

{}: 大括号中的函数体

“=”并不只是用来分割函数签名和函数体的,它的另一个作用是告诉编译器是否对函数的返回值进行类型推断!如果省去=,则认为函数是没有返回值的!

例如:

scala> def myFirstMethod() = { “exciting times ahead” }
myFirstMethod: ()java.lang.String
##缺少等号时,表名该方法是没有返回值的
scala> def myFirstMethod(){ “exciting times ahead” }
myFirstMethod: ()Unit

def 方法名(参数名:参数类型):返回值类型={

方法体

}

注意: 方法体内的最后一行为返回值,不需要使用return (和java不同)

如果最后一行是赋值或者输出语句,则没有返回值;

赋值语句和输出语句返回值类型为: Unit (),即没有返回值;

示例:

def add(x:Int,y:Int):Int={

x+y

}

调用: add(2,4)

def tree()=2+3

调用 : tree 当一个方法没有入参,调用时可以省略括号,直接使用方法名就可以调用

方法中的参数:

默认参数

def sayName(name:String="lisi")={
    println(name)
  }
调用:  sayName()  注意,这个小括号不能省略,否则会报错;

命名参数

就是调用一个函数时,使用参数名来调用(这样即使参数顺序不一致也能调用成功)

可变参数

def addkebian(numbers:Int*):Int={
    var result=0
    for(number <- numbers){
      result += number
    }
    result
  }
调用: addkebian(1,2,3,4)

 

三:scala中的方法和函数对比

Scala 有函数和方法,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。

这两者主要区别如下:

区别一:方法可以作为一个表达式的一部分出现(调用函数并传参),但是方法(带参方法)不能作为最终的表达式,但是函数可以作为最终的表达式出现。

scala> //定义一个方法

scala> def m(x:Int) = 2*x
m: (x: Int)Int

scala> //定义一个函数

scala> val f = (x:Int) => 2*x
f: Int => Int = <function1>

scala> //方法不能作为最终表达式出现

scala> m
<console>:9: error: missing arguments for method m;
follow this method with `_‘ if you want to treat it as a partially applied function
              m
              ^

scala> //函数可以作为最终表达式出现

scala> f
res9: Int => Int = <function1>

无参方法可以作为最终表达式出现,其实这属于方法调用,scala规定无参方法的调用可以省略括号,所以这

并不违法上面的说法;

scala> def m1()=1+2
m1: ()Int

scala> m1
res10: Int = 3

区别二:参数列表对于方法是可选的,但是对于函数是强制的。

scala> //方法可以没有参数列表

scala> def m2 = 100;
m2: Int

scala> //方法可以有一个空的参数列表

scala> def m3() = 100
m3: ()Int

scala> //函数必须有参数列表,否则报错

scala> var f1 =  => 100
<console>:1: error: illegal start of simple expression
       var f1 =  => 100
                 ^

scala> //函数也可以有一个空的参数列表

scala> var f2 = () => 100
f2: () => Int = <function0>

即参数列表对于函数来说是必须的,哪怕这是一个空的参数列表;

区别三:方法名意味着方法调用,函数名只是代表函数自身。

因为方法不能作为最终的表达式存在,所以如果你写了一个方法的名字并且该方法不带参数(没有参数列表或者无参) 该表达式的意思是:调用该方法得到最终的表达式。

因为函数可以作为最终表达式出现,如果你写下函数的名字,函数调用并不会发生,该方法自身将作为最终的表达式进行返回,如果要强制调用一个函数,你必须在函数名后面写()

scala> def m1()=1+2       //定义一个空参方法
m1: ()Int

scala> def m2 = 100;    // 定义个无参方法
m2: Int

scala> var f2 = () => 100  // 定义一个空参函数
f2: () => Int = $$Lambda$1047/510873326@1e191150

scala> m1               //调用一个空参方法
res3: Int = 3

scala> m2			   //调用一个无参方法
res4: Int = 100

scala> f2      //得到函数自身,不会发生函数调用
res5: () => Int = $$Lambda$1047/510873326@1e191150

scala> f2()    // 需要使用函数名()的形式才会发生函数调用
res6: Int = 100

为什么在函数出现的地方我们可以提供一个方法?

在scala中很多高级函数,如map(),filter()等,都是要求提供一个函数作为参数。但是为什么我们可以提供一个方法呢?就像下面这样:

scala> val myList = List(3,56,1,4,72)
myList: List[Int] = List(3, 56, 1, 4, 72)

scala> // map()参数是一个函数

scala> myList.map((x) => 2*x)
res15: List[Int] = List(6, 112, 2, 8, 144)

scala> //尝试给map()函提供一个方法作为参数

scala> def m4(x:Int) = 3*x
m4: (x: Int)Int

scala> //正常执行

scala> myList.map(m4)
res17: List[Int] = List(9, 168, 3, 12, 216)

这是因为,如果期望出现函数的地方我们提供了一个方法的话,该方法就会自动被转换成函数。该行为被称为ETA expansion。

这样的话使用函数将会变得简单很多。

利用这种自动转换,我们可以写出很简洁的代码,如下面这样

scala> val list = List(1,2,10,34,56)    // 定义一个list集合
list: List[Int] = List(1, 2, 10, 34, 56)
//10.< 被解释成obj.method,即整形的<的方法,所以该表达式是一个方法,会被解释成函数
scala> list.filter(10.<)   
res9: List[Int] = List(34, 56)

因为在scala中操作符被解释称方法

  • 前缀操作符:op obj 被解释称obj.op
  • 中缀操作符:obj1 op obj2被解释称obj1.op(obj2)
  • 后缀操作符:obj op被解释称obj.op

你可以写成10<而不是10.< 所以上面有多种写法:

list.filter(10<) 或者 list.filter(10.<) 或者 list.filter(10.<_)

如何强制把一个方法变成函数?

可以在方法名后面加一个下划线强制变成函数

四:方法(函数)使用过程中一些细节问题

  • 函数的形参列表可以是多个, 如果函数没有形参,调用时 可以不带()
  • 形参列表和返回值列表的数据类型可以是值类型和引用类型。
  • Scala中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下,return关键字可以省略。
  • 因为Scala可以自行推断,所以在省略return关键字的场合,返回值类型也可以省略;
  • 如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,这时要明确写成 : 返回类型 = ,当然如果你什么都不写,即使有return 返回值也为()
  • 如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值
  • 如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any)
  • Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:函数中可以再声明/定义函数,类中可以再声明类 ,方法中可以再声明/定义方法

示例如下:

object Demo3 {
  def main(args: Array[String]): Unit = {
    def f1(): Unit ={
      println("main方法中的f1方法:")
    }
    def sayok(): Unit ={    // 编译之后是  private final sayok$1
      println("main方法中的sayok方法。。。")
      def sayok(): Unit ={   // 编译之后是  private final sayok$2
        println("sayok方法中嵌套sayok方法")
      }
    }
  }
  def sayok(): Unit ={
    println("类中的sayok方法。。。")  // 编译之后是  sayok
  }
}

反编译之后:

 

  • Scala函数的形参,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值。
  • 如果函数存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆盖默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数
  • scala 函数的形参默认是val的,因此不能在函数中进行修改.
  • 递归函数未执行之前是无法推断出来结果类型(即递归函数不能使用自动推导),在使用时必须有明确的返回值类型

 

 

 

 

 

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值