【大学生博客大赛】

2021/4/19 18:57:07

本文主要是介绍【大学生博客大赛】,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Scala语言学习

文章目录

Scala介绍

【大学生博客大赛】

官方网址:http://www.scala-lang.org
官网对scala的介绍:Scala既是面向对象的语言,也是面向函数的语言。
scala可以为你在做大量代码重用和扩展是提供优雅的层次结构,并可以通过高阶函数来实现这样的目标。
【大学生博客大赛】

    Scala创始人 Martin Odersky 马丁·奥德斯基

Martin是EPFL(瑞士领先的技术大学)Martin是EPFL(瑞士领先的技术大学,洛桑联邦理工学院)编程研究组的教授。他在整个职业生涯中一直不断追求着一个目标:让写程序这样一个基础工作变得高效、简单、且令人愉悦。
他可能比世界上任何一个人写过更多的Java和Scala代码。他编写了javac,这是目前大部分Java程序员所使用的编译器。他也编写了Scala编译器scalac,可谓是Scala社区飞速发展的基石。他著有《Programming in Scala》一书,是最畅销的Scala书籍。他曾经就职于IBM研究院、耶鲁大学、卡尔斯鲁厄大学以及南澳大利亚大学。在此之前,他在瑞士苏黎世联邦理工学院追随Pascal创始人Niklaus Wirth学习,并于1989年获得博士学位。

scala语言的特点

Scala并不适于编程的初级课程。相反,它是为专业程序员定制的强力语言。
1、它是一门现代编程语言,作者是Martin Odersky(javac之父),受到Java、Ruby、Smalltalk、ML、Haskell、Erlang等语言的影响。
2、它即是一门面向对象(OOP)语言,每个变量都是一个对象,每个“操作符”都是方法。scala语言在面向对象的方面,要比java更彻底。
它同时也是一门函数式编程(FP)语言,可以将函数作为参数传递。你可以用OOP、FP,或者两者结合的方式编写代码。
3、Scala代码通过scalac编译成.class文件,然后在JVM上运行,可以无缝使用已有的丰富的Java类库。即Scala的代码会编译成字节码,运行在Java虚拟机(JVM)上。
4、接触语言的第一天你就能编出有趣的程序,但是这门语言很深奥,随着学习的深入,你会发现更新、更好的编写代码的方式。Scala会改变你对编程的看法。针对同一任务,可以有很多种不同的实现方式,并且可读性以及性能都有不一样的体现。

基础语法一

【大学生博客大赛】

基础语法二

语句 说明 示例
if……else if……else 判断 //一个简单的示例
var var1=10;
if是具有返回值的,if判断后,将执行代码的最后一个表达式的值返回作为整个if执行后的结果。 if(var1<100){
println("小了")
}else{
println("大了")
}

        //根据scala函数式编程风格,建议做如下更改
        //尽量使用常量
        val val1=10;
        //if……else最后一行的值是返回值,可省略return
        val result=
             if(val1<100){
               "小了";
             }else{
               "大了";
             }
        print(result)

        //也可以简化成下面的形式
        val val2=10;
        println(if(val2<100)"小了"else"大了");

while 和java中用法相同 //一个简单的例子
while无法控制返回值,或者说返回值是Unit,写成() val val1=List(1,2,3,4);
在scala中while比较少使用 var index=0;
while(index<val1.size){
println(val1(index));
index+=1;
}
for scala中的for要比java的for强大,使用很频繁,需要熟练掌握。 //生成一个1~100的区间,区间类型是range
for 同while一样,无法控制返回值,或者说返回值是Unit,写成() val val1=1 to 100;

但是:for()可以和yield{ }配合使用,将for()每次循环结果存到一个Vector(  )中。        //循环遍历并打印
        for(num <-val1){
          println(num)
        }

        //支持条件过滤
        for(num<-val1;if num>50){
          println(num)
        }

        //支持多条件过滤
        for(num<-val1;if num>50;if num%2==0;if num<90)
          println(num)

       //也可以写成下面的形式
        for(num<- 1 to 100;if num>50&&num<90&&num%2==0){
          println(num)
        }

        //实现9*9乘法表
        for(a<-1 to 9){
          for(b<-1 to a){
            print(b+"*"+a+"="+b*a+"\t");
          }
          println();
        }

        //可以简化为下面的写法
       //这种形式成为流间变量定义
        for(a<-1 to 9;b<-1 to a; val s=if(b==a)"\r\n"else"\t"){
            print(b+"*"+a+"="+b*a+s)
        }

      //引入yield函数,这类循环叫做for推导式
    //此外,如果yield 只有一行返回值,则{}可以省略
     val result=for(a<-1 to 9;b<-1 to a; val flag=if(b==a)"\r\n"else"\t")yield {b+"*"+a+"="+b*a+flag}
    println(result)

//一个有趣的案例
var v1=Array("apple","banana","orange")
for(i<-0 to v1.length-1){
println(s"$i is ${v1(i)}") }

    > 0 is apple
    1 is banana
    2 is orange

    //用s函数改造99乘法表
    for(a<-1 to 9;b<-1 to a; val s=if(b==a)"\r\n"else"\t"){
           print(s"$b*$a=${b*a}$s")  

    //遍历一个Map
    var v2=Map("key1"->"rose","key2"->"tom","key3"->"jary")
         for((k,v)<-v2){
         print(s"$k:$v")
         }

try catch finally scala中继承了java的异常机制 import java.lang
try {
throw new RuntimeException("error");
}catch {
case t: NullPointerException => t.printStackTrace();("空指针异常");
case t: Exception=>t.printStackTrace();println("其他异常");
}finally {
println("资源释放")
}
match scala中的match类似于其他语言的switch //一个简单的例子
//match匹配到case后,执行case对应的内容,然后退出match,于java不同的是,不需要写break
val val1="bbb";
val1 match {
case "aaa" =>println("1");
case "bbb" =>println("2");
case _ =>println("3");
}

        //此外,match可以带有返回值
        val result=val1 match{
          case "aaa" =>1
          case "bbb" =>2
          case  _ =>3
        }

break scala中没有break和continue语句,需要通过另外的形式来实现 import util.control.Breaks._
continue
object Demo12 {
def main(args: Array[String]): Unit = {

         //实现break
         breakable( 
       for(i <- 1 to 10){
           if(i==8){
              break();
           }else{
             println(i);
           }
         }

             )

         //实现continue
         for(i<-1 to 10){
           breakable(
            if(i==8){
              break;
            }else{
              println(i);
            }
           )
         }

      }
    }

【大学生博客大赛】

Scala函数—上篇

函数的声明
scala 函数通过 def 关键字定义,def前面可以具有修饰符,可以通过private、protected来控制其访问权限。
注意:没有public,不写默认就是public的。 此外也可跟上override,final等关键字修饰。

函数的返回值
1)函数体中return关键字往往可以省略掉,一旦省略掉,函数将会返回整个函数体中最后一行表达式的值,这也要求整个函数体的最后一行必须是正确类型的值的表达式。
2)大部分时候scala都可以通过 =符号 来自动推断出返回值的类型,所以通常返回值类型声明可以省略。
但是注意:如果因为省略了返回值类型造成歧义,则一定要写上返回值声明。
3)如果函数体只有一行内容,则包裹函数体的大括号可以省略
4)如果返回值类型是UNIT,则另一种写法是可以去掉返回值类型和等号,把方法体写在花括号内,而这时方法内无论返回什么,返回值都是 UNIT。

格式:[private/protected] def 函数名(参数列表):返回值声明 = {函数体}
示例:
//方法的返回值为空
def f1():Unit={
println("hello scala");
}
//等价于f1()方法,注意:如果函数没有=号,无论函数体里的返回值是什么,函数的返回值都是Unit
def f2(){
println("hello scala");
}
//定义方法参数类型,返回值类型,及返回值
def f3(a:Int,b:Int):Int={
a+b;
}

//scala可自行推断返回值类型,所以可省略返回值类型
def f4(a:Int,b:Int)={
a+b;
}
//如果函数体只一行内容,可以省了花括号
def f5(a:Int,b:Int)=a+b

//注意下面这种形式,因为没有=号,所以函数的返回值是Unit,即()
def f6(a:Int,b:Int){
a+b
}

默认参数
代码示意:
object Demo21 {

def f1(a:String,b:String="[",c:String="]")={
b+a+c
}
def main(args: Array[String]): Unit = {
print(f1("hello"))//将打印:[hello]
}
}

函数的种类
1.成员函数
2.本地函数(内嵌在函数内的函数)
3.函数值(匿名函数)
4.高阶函数

成员函数: 函数被使用在类的内部,作为类的一份子,称为类的成员函数
示例:
object Demo15 {

def main(args: Array[String]): Unit = {
val p=new Student();
p.eat();
p.study();
}

// eat() 和study()属于 类Student的成员函数
class Student{
def eat(){
println("吃饭")
}

def study(){
  println("学习")
}

}
}

本地函数:函数内嵌的函数称为本地函数,这样的函数外界无法访问
示例:
object Demo16 {

def main(args: Array[String]): Unit = {
val p=new Student();
p.eat("肉");

}

class Student{

def eat(food:String){
  //cook函数内嵌在eat函数里,这样的函数称之为本地函数
  def cook(food:String):String={
    "做熟了的"+food;
  }
  println("吃"+cook(food));
}

}
}

函数值 - 匿名函数:
示例:

def f1(a:Int,b:Int):Int={a+b};

//等价于上式的函数
(a:Int,b:Int)=>{a+b};

//如果函数体只有一行代码,可以省去大括号
(a:Int,b:Int)=>a+b;

//如果函数参数列表只有一个参数,小括号有可以省略
a:Int=>a+1;

//如果函数的参数类型可以被推测,则可以省略类型值
//(a,b)=>a+b

def f1(a:Int,b:Int):Int={a+b};
//可以将f1()函数赋值给f2常量
val f2=f1(_,_);

//可以将f1()函数赋值给f3变量,f3可以更改此函数
var f3=f1(_,_);
f3=(a:Int,b:Int)=>a*b;

//也可以这样写
val f4=(c:Int,d:Int)=>{c+d}

//注意,下面的写法是将f1的函数值复制给f5,而不是函数赋值给f5 
val f5=f1(2,3)

Scala函数-下篇

高阶函数:函数可以作为方法的参数进行传递和调用
示例1:
object Demo01 {

//定义了compute函数,a,b和f函数 三个参数。其中f函数未做实现。
//我们的目的是对传入的a和b参数利用 f函数做运算,但是具体是什么运算需要由用户自己来指定。
def compute(a:Int,b:Int,f:(Int,Int)=>Int):Int={
f(a,b)
}

def main(args: Array[String]): Unit = {
val f1=(a:Int,b:Int)=>{a+b}
val f2=(a:Int,b:Int)=>{a*b}
val f3=(a:Int,b:Int)=>{a-b}
val f4=(a:Int,b:Int)=>{a/b}

//由下式可以看出,scala中,函数可以当做参数进行传递和调用
val result=compute(2,3,f1)

//下式等价于上式
//val result=compute(2,3,(a,b)=>{a+b})

}
}
示例2:
object Demo02 {

//定义了一个函数,作用是将用户处理后的字符串结果进行打印输出
def handleString(a:String,f:(String)=>String){
println("处理完后的字符串为:"+ f(a))

}

def main(args: Array[String]): Unit = {
val a="hello scala";

handleString(a,(a)=>{a});
handleString(a,(a)=>{a.substring(6)});
handleString(a,(a)=>{a.concat(" 1706")})

}
}

占位符:占位符指的是scala中的下划线_ ,可以用它当作一个或多个参数来使用。
使用_占位符的前提要求:每个参数在函数仅出现一次。
使用下划线时,如果类型可以自动推断出,则不用声明类型。如果无法自动推断类型,则在下划线后自己来显示声明类型即可。
示例1:
object Demo03 {
def compute(a:Int,b:Int,f:(Int,Int)=>Int):Int={
f(a,b)
}

def handleString(a:String,f:(String)=>String){
println("处理完后的字符串为:"+ f(a))

}

def main(args: Array[String]): Unit = {
val message="hello scala";

//这样用占位符会报错
//handleString(message,(_)=>{_.substring(6)})

//应改为下面的写法
handleString(message,{_.substring(6)})

//如果函数体只有一行代码,则还可以将大括号去掉
 handleString(message,_.substring(6))

//compute的代码可简化如下  
compute(2,3,_+_)
compute(2,3,_*_)
compute(2,3,_-_)

//    此外
//    val f1=(a:Int,b:Int)=>{a+b}
//    等价于下式:
//    val f1=(_:Int)+(_:Int)
//    compute(2, 3, f1)

//再来看一个例子
val list=List(1,3,5,7,9)

list.foreach { x =>print(x) }
list.foreach { _ =>print(_) }
list.foreach { print(_) }

list.foreach { x => x*2 }
list.foreach { _*2 }

}
}

递归

示例1:
object Demo07 {

//从1开始做加法,只加偶数,当加和累计超过50时,结束递归
//示意:2+4+6……

def f1(num:Int,sum:Int):Int={
if(sum>50) return sum;
if(num%2==0){f1(num+1,sum+num)}
else {f1(num+1,sum)}

}
def main(args: Array[String]): Unit = {
//num是用户传入的初始值=1,sum是最后求得的和,初始值是0
val result=f1(1,0)
println(result)
}
}

示例2,用递归方式实现斐波那契数列
//0 1 1 2 3 5 8 13

def f2(n:Int):Int={
if(n==0) return 0
if(n==1) return 1
else f2(n-1)+f2(n-2)
}
f2(6)

示例3——2 3 4 9 16 81 ?

// n的取值:f(0) f(1) f(2) f(3) f(4) f(5)
//当n为偶数时,f(n)=f(n-2)f(n-2)
//当n为奇数是,f(n)=f(n-2)
f(n-2)

def f3(n:Int):Int={
if(n==0) return 2
if(n==1) return 3
else f3(n-2)*f3(n-2)
}

示例4——函数值:2 3 4 9 8 27 16 ?
//当n为偶数时,f(n)=2f(n-2)
//当n为奇数是,f(n)=3
f(n-2)

def f4(n:Int):Int={
if(n==0) return 2
if(n==1) return 3

if(n%2==0)2*f4(n-2)
else 3*f4(n-2)

}

示例5——求 1~n的数字之和

//1 3 6 10 15
//f(0) f(1) f(2) f(3) f(4)
//f(n)=f(n-1)+n+1

def f5(n:Int):Int={
if(n==0) return 1
else f5(n-1)+n+1
}

示例6—给定一个初始值n,并设定sum的初始值为0,当求和sum>12时结束递归

//0 1 3 6 10 15
//f(0,0)——n=0,sum=0
//f(1,1)——n=1,sum=1
//f(2,3)——n=2,sum=3
//f(3,6)——n=3,sum=6
//f(n+1,sum+n)

def f6(n:Int,sum:Int):Int={
if(sum>12)return sum
else f6(n+1,sum+n)
} //> f6: (n: Int, sum: Int)Int

f6(0,0) //> res3: Int = 15

示例7:
//给定一个scope范围,计算0~scope范围的整数之和,
//当和>12或者达到scope边界时,结束递归
def f7(n:Int,sum:Int,scope:Int):Int={
if(sum>12)return sum
if(n-1==scope)return sum
else f7(n+1,sum+n,scope)

} //> f7: (n: Int, sum: Int, scope: Int)Int

f7(0,0,4) //> res4: Int = 10

scala中,如果在递归时,保证函数体的最后一行为递归调用,则称这样的递归为尾递归。
scala会针对尾递归做优化处理,所以建议在写递归时写成尾递归形式

函数式编程的概念

编程范式
函数式编程是一种编程范式,我们常见的编程范式有:
1)命令式编程(Imperative programming),常见的面向对象编程是也是一种命令式编程。比如java,c等。
命令式编程是完全依托于冯诺依曼体系机来实现的,即代码最后会转变为一条条的指令去执行,所以指令式编程的时间复杂度是和指令数相关的。根据摩尔定律,冯诺依曼体系机的性能可能本世纪30年代就不再提高,即当冯诺依曼体系机被淘汰时,指令式编程可能也会被淘汰。现在有一个名字就是:冯诺依曼瓶颈,即内存的速度跟不上cpu处理速度。IBM TrueNorth。

2)函数式编程,从理论上来说,函数编程是不依托于指令架构的,因为函数式编程是建立主体和主体之间的映射关系。但是目前从实际情况来开,函数式编程还是需要转变为指令去运行的。
函数式编程语言:HasKell,K#,Lisp
3)逻辑式编程,最常用的逻辑编程语言是Prolog,另外有较适用于大型方案的Mercury。

函数式编程
在函数式语言中,函数作为一等公民,可以在任何地方定义,在函数内或函数外,可以作为函数的参数和返回值,可以对函数进行组合。这个概念就是——高阶函数,高阶函数就是参数为函数或返回值为函数的函数。有了高阶函数,就可以将复用的粒度降低到函数级别,相对于面向对象语言,复用的粒度更低。

此外,函数式语言通常提供非常强大的集合类(Collection),提供很多高阶函数,因此使用非常方便。

函数式编程语言还提供惰性求值(Lazy evaluation,也称作call-by-need),是在将表达式赋值给变量(或称作绑定)时并不计算表达式的值,而在变量第一次被使用时才进行计算。这样就可以通过避免不必要的求值提升性能。

纯函数式编程语言中的变量的值是不可变的(immutable),也就是说不允许像命令式编程语言中那样多次给一个变量赋值。比如说在命令式编程语言我们写“x = x + 1”,这依赖可变状态的事实,拿给程序员看说是对的,但拿给数学家看,却被认为这个等式为假。

懒值Lazy

懒值 lazy 当val被声明为lazy时,它的初始化将被推迟,直到我们首次对它取值。

懒值对于开销较大的初始化语句而言十分有用

【大学生博客大赛】

柯里化Currying

scala的柯里化的作用是结合scala的高阶函数,从而允许用户自建立控制结构。

柯里化(Currying)技术 Christopher Strachey 以逻辑学家 Haskell Curry 命名的(尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的)。它是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。

案例1:
object Demo08 {

def main(args: Array[String]): Unit = {
//首先我们定义一个函数:
def f1(a:Int,b:Int):Int={a+b}

//现在我们把这个函数变一下形:
def f2(a:Int)(b:Int)={a+b}
//那么我们应用的时候,应该是这样用:f2(2)(3),最后结果都一样是5,这种方式(过程)就叫柯里化。
val r1=f2(2)(3)

//柯里化实质上会演变成这样一个函数:
//接收一个参数a,返回一个匿名函数,
//该匿名函数又接收一个参数b,函数体为a+b
def f3(a:Int)=(b:Int)=>a+b

val f4=f3(2)
//请思考 f4(3)的值是多少?答案是:5
f4(3)

}
}

示例2:
object Demo09 {

def f1(a:Int,b:Int,c:Int):Int={a+b+c}

def f2(a:Int)(b:Int)(c:Int):Int={a+b+c}

def f3(a:Int)(b:Int,c:Int):Int={a+b+c}

def f4(a:Int,b:Int)(c:Int):Int={a+b+c}

def main(args: Array[String]): Unit = {
//f1和f2的函数的体现的是传入三个数,马上得到结果
f1(1,2,3)
f2(1)(2)(3)

//f3函数则可以体现:延迟执行的思想以及固定易变因素的思想
val r1=f3(1)(2,3)

}
}

示例3:
object Demo10 {

def f1(a:Int,b:Int,f:(Int,Int)=>Int):Int={f(a,b)}

def f2(a:Int)(b:Int)(f:(Int,Int)=>Int):Int={f(a,b)}

def f3(a:Int,b:Int)(f:(Int,Int)=>Int):Int={f(a,b)}

def f4(a:Int)(b:Int,f:(Int,Int)=>Int):Int={f(a,b)}

def main(args: Array[String]): Unit = {
//调用f3
f3(2,3){(a:Int,b:Int)=>a+b}
//可简化为下面的形式,我们发现这和scala中很多函数的形式很相近,比如:for(x<-1 to 10){print()}
//所以,柯里化的另外一个作用是让用户灵活的自义定自建控制结构
f3(2,3){
+}
f3(2,3){
*_}
// 延迟处理思想
def f3(a:Int)=(b:Int)=>a+b
val f4=f3(2)
f4(3)

}

}

总结柯里化的作用

柯里化技术在提高适用性、延迟执行或者固定易变因素等方面有着重要重要的作用,加上scala语言本身就是推崇简洁编码,使得同样功能的函数在定义与转换的时候会更加灵活多样。另外在Spark的源码中有大量运用scala柯里化技术的情况,需要掌握好该技术才能看得懂相关的源代码。

在scala柯里化中,闭包也发挥着重要的作用。所谓的闭包就是变量出了函数的定义域外在其他代码块还能其作用,这样的情况称之为闭包。就上述讨论的案例而言,如果没有闭包作用,那么转换后函数其实返回的匿名函数是无法在与第一个参数a相关结合的,自然也就无法保证其所实现的功能是跟原来一致的。



这篇关于【大学生博客大赛】的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程