Scala学习笔记(2)

一、控制结构和函数

---------------------------------------------------------------

1、条件表达式

 (1) 在Scala中if/else的表达式都是有值的,这个值就是跟在if或者else之后的表达是的值

  eg: if(x >0) 1 else -1  //上面表达式的值是1或者-1,具体是哪个值取决于x的值

  

 (2) 可以将if/else表达式的值赋给变量

  val s = if (x > 0) 1 else -1   <===>if(x>0) s = 1 else s =-1  //相对而言,前面的一种写法会更好,因为其可以用来初始化一个val,而在后面的s必须是var类型,这个地方x是常量不能再进行赋值了

  java表达式:x>0?1 : -1    //Java或C++  <===>if(x > 0 )1 else -1

  (3)在Scala中,每个表达式都有一个类型。举例来说,表达式if(x>0) 1 else -1 的类型是Int,因为这里的两个表达式都是Int

    而:if (x>0) "positive" else -1   //这个表达式的类型是两个分支类型的公共超类。这里第一个分支是java.lang.String

    而另外一个 分支是Int类型。所以这里的公共超类是Any

    这里如果else部分缺失了:if (x>0) 1    //那么有可能if语句没有输出值。但是在Scal中,每个表达式都应该有某种值,这个问题的解决方案是引入一个Unit类,写作()。

    不带else的if语句等同于if (x> 0 ) 1 else ()  //()表示的是"无有用值"的占位符,可以将Unit当做Java或C++中的void

  (4)注意:REPL比起编译器来更加的"近视",在同一时间只能看到一行代码。

      eg: if(x>0) 1

        else if (x==0) 0 else -1    //这里REPL会执行if(x>0) 1 ,然后就显示结果,而之后看到接下来的    else    关    键    字  就会不知所措

    如果想在else前面换行的话,需要用到花括号

    if(x > 0){1

      } else if (x==0) 0 else -1 

    如果想在REPL中粘贴成块的代码,而又不想近视问题,可以使用粘贴模式。键入:paste,把近视代码粘贴进去,然后按下Ctrl + D。这样REPL会把整个代码块当做一个整体来进行分析

  (5)条件表达式,scala的表达式有值,是最后一条语句的值

    scala>val x =1 ;

    scala > val b = if (x>0) 1 else -1 ;

  (6)val xx = if(x>0) 1 else "hello"  //这个地方的返回值是Any类型  xx:Any =1,Any是Int和String的创造类

    参数的强转: 1.toString    //将数值类型的转换成字符串类型String类型  

          "1000".toInt   //将字符串类型转换成Int类型

  (7)赋值语:val y = (s =1 )    //赋值语句为空,y:Unit =()  类似于java中的void

  (8)粘贴模式:scala>:paste

          if(x>0) {

           1  } else -1

//      ctrl + D  //退出粘贴模式

  (8)java语言的编码运行过程:*.java ----->*.class----------->程序

2、语句终止:Scala与其他的脚本语言相类似,行尾的位置不需要分号。在}、else以及类似的位置也不需要写分号,只要能从上下文明确的判断出这里是语句的终止就可以

  (1)如果在单行中能够写下多个语句,就需要用分号将他们分割开来

    if ( n > 0 ) {r = r * n ; n-=1}

  (2)如果写较长的语句,需要分成两行来写的话,就需要确保第一行以一个不能用作语句结尾的符号作为结尾,一般来说是比较好的选择是操作符:

  s = s0 +(v - v0)* t +

    0.5*(a-a0)*t*t

  (3)Scala程序员们更加倾向于使用花括号来进行相关的处理:

    if(n > 0){

      r = r*n

      n -=1

     }      //这个地方可以知道,以{结束的行很清楚的表示了后面还有很多的内容

3.块表达式和赋值

  在java中快语句是包含在{}中的语句序列。当需要在逻辑分支或循环中放置多个动作的时候,可以使用快语句。

  在Scala中,{}块包含一系列的表达式,结果也是一个表达式。快中最后一个表达式的值就是块的值

  eg:val distance = {val dx = x -x0 ; val dy = y -y0 ; sqrt (dx * dx + dy * dy)}

  {}块的取值取其最后一个表达式,在此处粗体标出。变量dx和dy仅作为计算所需的中间值

  在Scala中,赋值动作本身是没有值的,或者说,他们的值是Unit类型的,Unit类型等价于java中的void,而这个类型只有一个值,写作()。一个以赋值语句结束的块,比如{r =r * n; n -=1)的值是Unit类型的

   Unit<===>void

 

4、输入和输出

  (1).打印一个值,需要用print或者println函数进行相关的打印,而后者在打印完成后会追加一个换行符。

    print("answer:")    //打印

    println(43)      //换行打印

  //输出

  Scala>print("hellp")

  Scala>println("hello")

  Scala>val password = readLine("请输入密码");

5、循环

  Scala拥有和java相同的while和do循环

  通过粘贴模式来写循环。(while)

var i = 0;
while
(n>0){ r= r*n n-=1 }

通过Scala语言打印出99乘法表

  

var i = 1;
while(i<10){
  var j = 1;
  while(j<=i){
  print(i+"*"+j+"="+(i*j)+"    ");
  j+=1;          
  }     
  println();
  i+=1;       
}

  百钱买百鸡问题

//百钱买白鸡
100块钱买100只小鸡
公鸡:5块钱/只
母鸡:3块钱/只
小鸡:1块钱/3只

var cock=0;
while(cock <= 20){
var hen = 0 ;
while(hen <=100/3){
var chicken =0;
while(chicken<=100){
var money=cock*5 + hen*3 +chicken*(1/3);
var mount = cock + hen + chicken;
if(money==100 && mount==100){
println("cock:"+cock+","+"hen:"+hen+","+"chicken:"+chicken);
}
chicken+=3;
}
hen+=1;
}
cock+=1;
}


 

Scala加载Scala类的方法:load d:\scala\buy.scala

  (2)for循环

  

for(x<-1 to 10) println(x)
语法:
    for(i<- 表达式)    //这个地方1 to n 这个调用返回1到n之间的区间的Range
//让变量i便利<-右边的表达式的所有制。至于这个便利具体如何执行,取决于表达式的类型。

  在便利字符串或者数组的时候,通常需要使用0到n-1的区间。这个时候可以用util方法而不是to方法。util方法返回一个并不包含上限的区间。

  

val s ="hello"
var sum = 0
for(i <- 0 util s.length){    sum +=s(i)}
println(sum);
  

可以使用breaks对象的break方法

 

6、可以使用变量<-表达式的形式提供多个生成器,用分号将其分隔开来。

  for高级循环

for(i<- 1 to 3 ;j<- 1 to 3) println((10*i+j)+" ")

  这个地方每一个生成器都可以带一个守卫,以if开头的Boolean表达式:

  

for(i<- 1 to 3 ; j <- 1 to 3 if i!=j) print((10*i+j)+" ")

如果for循环的循环体外面以yield开始,则循环会构造一个集合,每次都迭代集合中的一个值

  

for(i < -1 to 10) yeild i%3   //这样的for循环叫做for循环推倒式

7、函数

Scala除了方法之外还支持函数。方法对对象进行操作,函数不是,如果要定义函数,需要给出函数的名称、参数和函数体

  

def abs(x:Double)=if(x>=0) x else -x

如果函数体需要多个表达式完成,可以用代码块。快中最后一个表达式就是函数的返回值。

def fac(n:Int)={
    var r =1
    for(i<- 1 to n) r= r*i
    r
   }

本例中返回值是r,但是没有return 这个关键词

但是对于递归函数,我们必须制定返回值类型。

  def fac(n:Int):Int=if(n<=0) 1 else n*fac(n-1)  //这个地方的递归函数必须制定返回值类型,如果没有进行指定,Scala编译器就没有办法校验n*fac(n-1)的数据类型了

  定义函数:

  def add (a:Int,b:Int):Int = {

    var c =a+b ;

    return c;

}

在:paste模式下进行粘贴,最后会得到add(a:Int,b:Int)Int,即是参数类型是Int型,返回值类型也是Int型

  定义递归:

  def fac(n:Int):Int= if(n==1) 1 else n*fac(n-1);    //定义了n的阶乘,递归的函数必须显示定义返回值类型

  8.默认参数和带名参数

  (1)eg:def decorate(str:String,left:String="[",right:String="]")= left+str+right;

  如果调用decorate("hello")  ===>["Hello"]

  或者:def decorate(prefix:String,str:String,suffix:String)={  //默认不带参

    prefix+str+suffix    

  }

  //这个地方的调用:最少要带上两个参数,decorate("hello","world");最终把最后的括号带上了

  //或者指定给哪个参数进行传参,decorate(str="hello")

  //或者给其他的参数进行相关的传参:scala>decorate(str="hello",prefix="<<"。最后的返回值是<<hello[]]

  def decorate(prefix:String="[[",str:String,suffix:String="]]")={  //默认带参数的

    prefix+ str+suffix

  }

  调用函数decorate("[[","hello","]]") ==============>[[hello]]

  (2)如果相对参数的数量的值不够,参数会从后面诸葛应用进来,如decorate("Hello",">>>")会使用right参数的默认值,

   得到">>>[Hello]"

def sum(args:Int*)={
    var result = 0
    for(arg <- args) result+=arg
    result
}

 

  (3)在提供参数值的时候指定参数名。如:

    decorate(left="<<<",str="Hello",right=">>>")    //最后的结果是<<<Hello>>>

  (4)带名参数可以让函数更加可读。

  (5)函数的默认值和命名参数

    scala>def decorate(prefix:String,str:String,suffix:String)={

      prefix + str +sufix

  }

9.变长参数

 (1)边长参数用法例子 

def sum(args:Int*)={
  var result = 0 
  for(arg<-args)  result+=arg
  result          
}

  val s = sum(1,4,9,16,25)  //这个地方函数得到的是一个类型为Seq的参数

  (2)如果已经有一个值的序列,则不能直接将其传入函数。如:var s =sum(1 to 5)  //错误

  val s = sum (1 to 5)  //错误,这个地方要注意,如果sum函数传入的是单个参数,那么参数必须是单个的整数,而不是一个整个的区间。解决的办法是告诉编译器,希望这个参数被当做参数序列进行处理。追加:_*,如下所示:

  val s =sum(1 to 5:_*)  //这个地方将1 to 5当做参数序列进行处理

  (3)在递归定义中会用到上面的语法:

    def recursiveSum(args:Int*):Int={    //在这里序列head是首个元素,而tail是所有其他元素的序列,这又是一个Seq,我们用_*来转换成参数序列

      if(args.length==0) 0 

      else args.head + recursiveSum(args:tail:_*)

  }

  

  (4)参数当做参数序列进行处理

def sum1(args:Int*):Int={
    if(args.length==0) 0
    else args.head+sum1(args.tail_*)
}

scala>add(1 to 10)    //错误

scala>add(1 to 10:_*)  //将1 to 10当做序列

10.过程:如果函数体包含在花括号中但是没有前面的=号,那么返回值类型就是Util。这样的函数成为过程

    过程不返回值,我们调用它仅仅是为了副作用

    (1)也可以进行这样的方式进行相关的定义:def box(s:String):Unit={

        ................

      }

def box(s:String){    //仔细看:这个地方没有=号
    var border="-" * s.length +"--\n"
    println(border+"|"+s+"\n"+border)
}

11.懒值

  当val被声明为lazy的时候,它的初始值将被推迟,知道我们首次对其进行取值

  lazy val words = 

 

12.异常处理

  try{

    "hello".toInt;

  }catch{

    case _:Exception =>print("xxx");

    case ex:java.io.IOException=>print(ex)

  }

  _      //通配符

  java.io._    //通配相当于*

  :_*      //1 to10:_*,转成序列

posted @ 2018-09-12 08:41  stone1234567890  阅读(445)  评论(0编辑  收藏  举报