Scala-函数及原理介绍

//方法是类的一部分,属于定义在类中的函数,惯用“方法”这个术语来指代类的成员
Scala 中函数和方法的区别:
Scala 中的方法跟 Java 的类似,方法是组成类的一部分,指代类的成员。
Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了Trait 的类的对象。
如果更明确划分的话,Scala 中使用 val 语句可以定义函数,def 语句定义方法。(但我们习惯 def 定义的不属于类的成员的,也称为函数)。
方法是一个以 def 开头的带有参数列表(可以无参数列表)的一个逻辑操作块,这正如 object 或者 class 中的成员方法一样。 
函数是一个赋值给一个变量(或者常量)的匿名方法(带或者不带参数列
表),并且通过=>转换符号跟上逻辑代码块的一个表达式。=>转换符号后面的逻
辑代码块的写法与 method 的 body 部分相同。 
所以,严格意义上来讲,“def”定义的任何东西本质上都是方法,并不是对象.
注意事项:
1.def 定义方法,val/var 定义对象。即使像“def a=0”,在调用时使用表达式“a”,仍然调用的是“a()”。 
2.方法不能作为单独的表达式而存在(参数为空的方法除外 而函数可以。 
3.函数必须有参数列表(可以为空),而方法则可以省略。如“def a=0”。 
4.方法名是方法调用,而函数名只是代表函数对象本身。 
5.在需要函数的地方,如果传递一个方法,自动把方法转换为函数

当然方法也可以手动转化为函数对象:val f2 = 方法

函数注意事项总结: 
1) 函数的形参列表可以是多个, 如果函数没有形参,调用时 可以不带()  
2) 形参列表和返回值列表的数据类型可以是值类型和引用类型。 
3) Scala 中的函数可以根据函数体最后一行代码自行推断函数返回值类型
def getSum(n1: Int, n2: Int): Int = { 
    n1 + n2 
} 
4) 因为 Scala 可以自行推断,所以在省略 return 关键字的场合,返回值类
型也可以省略 
def getSum(n1: Int, n2: Int) = { 
    n1 + n2 
  } 
5) 如果函数明确使用 return 关键字,那么函数返回就不能使用自行推断了,
这时要明确写成 : 返回类型 =  ,当然如果你什么都不写,即使有
return 返回值为() 
6) 如果函数明确声明无返回值(声明 Unit),那么函数体中即使使用 return
关键字也不会有返回值 
7) 递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的
返回值类型 
函数调用 
1.传值调用 
传值调用是默认的调用方式,表示对实参先计算结果,然后将结果代入函数
形参。 
def square(x: Int): Int = {  
    println(x)    //3 
    x * x             //计算 3*3 
} 
 
square(1+2)   //传值调用,先计算 1+2 
2.传名调用 
传名调用时,参数在调用时不会计算,只有真正用到参数时才计算。唯一的
优势是,如果函数体内未使用参数,则不用计算该参数表达式的值,可以提高一
些效率。如下代码所示: 
//使用 x: => Int 的定义方式 
def square(x:  => Int): Int = {  
    println(x)    //计算 1+2 
    x * x             //计算(1+2)*(1+2) 
} 
 
square(1+2)   //调用时不计算 
 
//函数定义
def 函数名([参数名:参数类型],…)[:返回类型]={  //返回类型为Unit的函数,称为过程(可省略=)
    函数体
     [return] 表达式
}

//函数为什么是scala的核心:
函数是一等公民,它们可以独立存在,你可以将其赋值给一个变量,或将他们当做参数传给其他函数
为什么需要使用函数:避免代码冗余,更利于代码的维护

//方式1: val 函数名=(参数列表)=> { 函数体 }  
//大括号可以省略val f1 = (x: Int, y: Int) => x + y
//方式1完整写法:val f11:(Int,Int)=>Int = (x: Int, y: Int) => { x + y}
//方式2:val 函数名: (参数列表) => 返回值类型 = {(参数列表)=>函数体 }
val f2:(Int,Int)=>Int = (x,y) => x+y
val f22:((Int,Int)=>Int) = {(x,y) => x+y}
//方式3:通过new定义val f3=new Function2[Int,Int,Int] { def apply(x: Int, y: Int): Int = x * y}
//方式4:不写参数名val f4:(Int,Int)=>Int = (_+_)

//定义一个函数/方法
def square(x: Int): Int = { 
    println(x)
    return x * x    //return可省略
}
Val f0=square _
//定义一个函数方式2
val f1 = (x:Int,y:Int) => x + y 
匿名函数定义
“=>”左边为参数列表,“=>”右边为函数体  :(参数列表)=>{函数体}
val f1=(x:Int)=>{println(x);x*x}  //将匿名函数赋值给变量f1
//省略函数名称val 函数名=(参数列表)=> { 函数体 }  则变为匿名函数,匿名函数定义:
(参数列表)=>{函数体}   具体形式示例:(x:Int,y:Int)=>x+y
包括三个部分:参数列表,右箭头和函数体。其中,参数列表可以为空,函
数体也可为空。那么最简化的函数字面量为:()=>{}。 
Scala函数字面量与Java中的Lambda表达式基本类似,只不过定法上由“->”
变成了“=>”。 

高阶函数
//函数作为参数
书写形式:     参数名:函数参数类型=>函数返回类型
def doSquare    (f:    Int   =>Int,p:Int)          =f(p)
def square(x:Int):Int=x*x
doSquare(square,square(2))
多个参数则为: 
参数名:(函数参数类型 1,函数参数类型 2,...)=>函数返回类型

如果一个函数的参数是函数,则必须为该参数传递一个函数值,类似“()=>{}”这样的函数字面量。
由于有编译器强制转换的存在,所以部分情况下只需要传递类或对象的方法即可。例如: 
List(1,2,3).foreach(println) 
***************************************
//函数作为返回值
//返回类型为函数(Int=>Int)
def doSquare()={
  (x:Int)=>x*x
}
doSquare()(2)

(4)使用占位符再精简 
函数字面量“x=>x+1”中参数 x 且仅使用过一次,可省略参数 x 定义,函数
体中使用占位符“_”表示参数 x

List(1,2,3).map(_+1
函数嵌套 :Scala函数内可以定义函数,函数内的函数也称局部函数或者内嵌函数
//使用函数嵌套实现阶乘运算
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)	//不能在factorial()之外调用
   }

柯里化(Currying):函数可以定义多个参数列表,当使用较少的参数列表调用多参数列表的函数时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化
https://docs.scala-lang.org/zh-cn/tour/multiple-parameter-lists.html

//单参数列表
def modN(n: Int,x: Int) = ((x % n) == 0)
//多参数列表
def modN(n: Int)(x: Int) = ((x % n) == 0)
//新函数接收剩余的参数列表作为其参数
def f1(x: Int) = modN(10)(x) 
def f2(n: Int) = modN(n)(10) 
def f3 = modN(10)(_)  

隐式参数 :方法可以具有隐式参数列表,由参数列表开头的implicit 关键字标记
implict只能修改最尾部的参数列表,应用于其全部参数
Scala可自动传递正确类型的隐式值
通常与柯里化函数结合使用
def sum(x:Int)(implicit y:Int)=x+y
implicit var a=10	//将作为Int类型隐式值自动传递
sum(10)	//20

隐式函数
这个规则非常简单,当编译器看到类型X而却需要类型Y,它就在当前作用域查找是否定义了从类型X到类型Y的隐式定义
implicit def double2Int(x:Double)=x.toInt
val i:Int=3.5

//常用高阶函数
val l=List(1, 2, 3, 4, 5, 6, 7, 8, 9)
l.map(_*2).foreach(println)
l.map(_*2).filter(_>8).foreach(println)
l.fold(0)((sum,i)=>sum+i)   //从0开始累加初始值的类型必须是list中元素类型的超类  初始值必须是中立的  对加法来说,中立的值是0;而对于乘法来说则是1
l.foldLeft(0)((sum,i)=>{println(sum,i);sum+i})  //从0开始累加  /:
l.foldRight(0)((sum,i)=>{println(sum,i);sum+i}) //从最后开始累加   :\
l.take(4).foreach(println)//非高阶
println(l.reduce(_+_))      l.reduce((x:Int,y:Int)=>x+y)
println(l.reduce(_-_))
println(l.max)
println(l.count(_>3))
println(l.min)
println(l.sum)

val a=List(1,2,3,4)
val b=List("A","B","C","D")
println(a zip b)	//List((1,A), (2,B), (3,C), (4,D))
val c=List("A","B","C","D","E")
println(a zip c)	//List((1,A), (2,B), (3,C), (4,D))  以最小为准
val d=List(1,2,3,4,5)
println(d zip c)
List("zhangsan","lisi","wangwu").zip(List(100,90,75,83))

val f=List(List(1,2),List(3,4),List(5,6))
println(f.flatten)   //List(1,2,3,4,5,6)
println(f.flatMap(_.map(_*2)))  //List(2, 4, 6, 8, 10, 12)

//综合应用
val l=Liyinyongst(1, 2, 3, 4, 5, 6, 7, 8, 9)
list.map(_.split(" ")).flatten
list.map(_.split(" "))
list.map(_.split(" ")).map(x=>(x,1))
list.map(_.split(" ")).map(x=>(x,1)).groupBy(x=>x._1)
list.map(_.split(" ")).map(x=>(x,1)).groupBy(x=>x._1).map(x=>(x._1,x._2.size))
list.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).map(x=>(x._1,x._2.size)).foreach(println)
list.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).map(x=>(x._1,x._2.size)).toList
list.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).map(x=>(x._1,x._2.size)).toList.map(x=>(x._2,x._1))
list.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).map(x=>(x._1,x._2.size)).toList.map(x=>(x._2,x._1)).sortBy(x=>x._1*(-1))
list.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).map(x=>(x._1,x._2.size)).toList.map(x=>(x._2,x._1)).sortBy(x=>x._1*(-1)).foreach(println)

//递归

//break

//package com.njbdqn.zb.kb07
import scala.io.StdIn
import scala.util.control.Breaks

object fun {
  def main(args: Array[String]): Unit = {
    //定义一个函数方式2
   // val f1 = (x:Int,y:Int) => x + y
    //{参数列表}=>{函数体}     匿名
  val x = StdIn.readInt()
    for (i<- 1 to x/2){
      for(j<- x/2-i to 0 by -1){
        print(" ")
      }
      for (z<- 1 to 2*i-1){
        print("*")
      }
      println()
    }
  }
  //.prt
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理实验,使用Scala编程语言进行分析是一种常见的做法。Scala是一门功能强大的多范式编程语言,它融合了面向对象编程和函数式编程的特性。 在编译原理实验,我们通常需要实现语言的词法分析和语法分析两个重要的步骤。词法分析器主要负责将源代码分解为各种词法单元,例如关键字、标识符、运算符和常量等。而语法分析器则根据词法单元构建语法树,以验证源代码是否符合给定的文法规则。 Scala提供了丰富的语言特性和工具,便于我们实现词法分析器和语法分析器。例如,我们可以使用Scala的正则表达式库来定义词法规则,并使用模式匹配语法来进行单词的匹配和提取。此外,Scala还支持高阶函数和匿名函数的特性,使得我们可以更方便地实现语法分析器。 除了词法分析和语法分析,编译原理实验还需要实现其他功能,如语义分析、间代码生成和目标代码生成等。Scala作为一门面向对象和函数式的编程语言,具有良好的可扩展性和可维护性,能够有效地支持这些功能的实现。 在实验过程,我们可以利用Scala的强类型系统和模式匹配等特性来提高代码的可靠性和可读性。此外,Scala还提供了丰富的工具库和框架,如ANTLR和ScalaTest等,可以进一步简化编译过程的实现和测试工作。 总之,使用Scala编程语言进行编译原理实验分析是一种有效和方便的选择。Scala的多范式特性、丰富的语言特性和工具支持,可以帮助我们实现词法分析器、语法分析器和其他编译器的各个部分,并提高代码的可读性和可维护性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值