zoukankan      html  css  js  c++  java
  • Scala实践5

    一、Scala的层级

    1.1类层级

    •    Scala中,Any是所其他类的超类,在底端定义了一些有趣的类NULL和Nothing,是所有其他类的子类。

        

    • 根类Any有两个子类:AnyVal和AnyRef。其中AnyVal是Scala里每个内建值类的父类

         

    scala> new Int
    <console>:12: error: class Int is abstract; cannot be instantiated
           new Int
    

      

    1.2底层类型

          在Scala类层级中,可看到scala.Null和scala.Nothing。它们是用统一的方式处理Scala面对对象类型的某些“边界情况”的特殊类型。

    •        Null类是null引用对象的类型,它是每个引用类的子类,Null不兼容值类型,例如,不能把null值赋给整数变量:
    scala> val i: Int = null
    <console>:11: error: an expression of type Null is ineligible for implicit conversion
           val i: Int = null
                        ^
    

      Nothing类型在Scala的类层级的最底层,它是任何其他类型的的子类型。Nothing的一个用处是它标明了不正常的终止。例如Scala的标准库中的Predef对象有一个error方法,如下定义:

    def error(message:Sring):Nothing=
      throw new RuntimeException(message)

       error 的返回类型是Nothing,告诉用户方法不是正常返回(是抛出异常)。因为Nothing是任何类的子类,所有可以灵活使用向error这样的方法,例如:

    scala> def error(message:String):Nothing =
         |  throw new RuntimeException(message)
    error: (message: String)Nothing
    
    scala> def divide(x:Int,y:Int):Int=
         | if(y!=0)  x/y  else error("can't divide by zero")
    divide: (x: Int, y: Int)Int
    
    scala> divide(7,2)
    res5: Int = 3
    
    scala> divide(7,0)
    java.lang.RuntimeException: can't divide by zero
      at .error(<console>:12)
      at .divide(<console>:13)
      ... 28 elided
    
    scala>
    

      

     二、函数和闭包

    2.1方法

    • 定义函数最通用是方法是作为某个对象的成员。这种函数被称为方法,作为例子:
     import scala.io.Source
      object LongLines{
         def processFile(filename:String,Int){
         val source = Source.fromFile(filename)
     for(line<-source.getLines)
      processFile(filename,width,line)
      }
     private def processFile(filename:String,Int,line:String){   
      if(line.length>width)
        println(filename+":"+line.trim)
      }
      
      }
      
      object FileLongLines{
         def main(args:Array[String]){
       val width=args(0).toInt
       for(arg<-args.drop(1))
        LongLines.processFile(arg,width)
      }
    }

    2.2本地函数

    上节processFile方法的建立演示了函数式编程的设计原则,问题是这些帮助函数的名称可能污染程序的命名空间。

    Scala中的解决方法:一种是私有方法。

    • 另一种是把函数定义在别的函数内。就好像本地变量那样,这种本地函数仅在包含它的代码块中可见。举例:
     def processFile(filename:String,Int){
     
            def processLine(filename:String,Int,line:String){   
      if(line.length>width)
        println(filename+":"+line.trim)
      }
         val source = Source.fromFile(filename)
     for(line<-source.getLines)
      processFile(filename,width,line)
      }
    

      

    例子中通过私有方法转化为局部方法,processLine的定义放在processFile定义里,作为本地函数,processLine的范围局限在processFile之内,外部无法访问。

    •    带局部processLine方法的LongLines

        

     def processFile(filename:String,Int){
     
            def processLine(line:String){   
      if(line.length>width)
        println(filename+":"+line.trim)
      }
         val source = Source.fromFile(filename)
     for(line<-source.getLines)
      processFile(line)
      }

    这种对外层函数入参的直接使用是Scala里通用的嵌套思想的平常但也很有用

    2.3头等函数

    Scala的函数是头等函数,不仅可以定义和调用函数,还可以把它们写成匿名的字面量,并把他们作为值传递,

     函数字面量被编译进类,并在运行期间实例化为函数值。因此函数字面量和值的区别在于函数字面量存在于原代码,而函数值作为对象存在于运行期。这个区别很像类(源代码)和对象(运行期)之间的关系。

    =>指明这个函数把左边的东西(任何整数x)转化为右边的东西。所有,这个函数可以把任何整数x映射为x+1

    函数值是对象,所有如果你愿意,可以将其存入变量。它们也是函数,所有你可以使用通常的括号函数调用它们。

    scala> var increase=(x:Int)=>x+1
    increase: Int => Int = $$Lambda$1149/268616862@62eb918
     
    scala> increase(4)
    res7: Int = 5
    

      

    2.4部分应用函数

    scala> val someNumbers=List(-11,-10,-5,0,5,10)
    someNumbers: List[Int] = List(-11, -10, -5, 0, 5, 10)
     
    scala> someNumbers.foreach(x:Int)
    <console>:13: error: not found: value x
           someNumbers.foreach(x:Int)
                               ^
    <console>:13: error: type mismatch;
     found   : Int
     required: Int => ?
           someNumbers.foreach(x:Int)
                                ^
     
    scala> someNumbers.foreach(x:Int)=>println(x)
    <console>:1: error: ';' expected but '=>' found.
           someNumbers.foreach(x:Int)=>println(x)
                                     ^
     
    scala> someNumbers.foreach((x:Int)=>println(x))
    -11
    -10
    -5
    0
    5
    10
     
    scala> someNumbers.filter((x:Int)=>x>0)
    res10: List[Int] = List(5, 10)
     
    scala> someNumbers.filter((x)=>x>0)
    res11: List[Int] = List(5, 10)
     
    scala> someNumbers.filter(x=>x>0)
    res12: List[Int] = List(5, 10)
     
    scala> someNumbers.filter(_>0)
    res13: List[Int] = List(5, 10)
     
    scala> val f=_+_
    <console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
           val f=_+_
                 ^
    <console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2: <error>) => x$1.$plus(x$2))
           val f=_+_
                   ^
     
    scala> val f=(_:Int)+(_:Int)
    f: (Int, Int) => Int = $$Lambda$1180/712034517@6d0ef6dc
     
    scala> f(2,6)
    res14: Int = 8

    部分应用函数是一种表达式,不需要提供需要的所有参数。代之以提供部分,或者不提供所需参数。

    闭包

    scala> (x:Int)=>x+more
    <console>:12: error: not found: value more
           (x:Int)=>x+more
                      ^
    //声明more
    scala> val more=1
    more: Int = 1
    scala> val addMore=(x:Int)=>x+more
    addMore: Int => Int = $$Lambda$1206/2005145495@773eb14c
    scala> addMore(5)
    res21: Int = 6
    

      

      依照这个函数字面量在运行时创建的函数值(对象)被称为闭包

    重复函数

      Scala中,可以指明函数的最后一个参数是重复的,从而允许客户向函数传入可变长度参数列表。想要标注一个重复参数,可在参数类型之后放一个星号。如:

    scala> def echo(args:String*)=
         |   for (arg<-args) println(arg)
    echo: (args: String*)Unit
     
    scala> echo()
     
    scala> echo("one")
    one
     
    scala> echo("one","hello!")
    one
    hello!
    函数内部,重复函数的类型是声明参数类型的数组。因此,echo函数被声明为类型“String*”的args的类型实际上是Array[String]。然而,如果你有一个合适的数组,并尝试把它当作重复参数传入,将得到编译器错误:
    scala> val arr=Array("What's","up","doc?")
    arr: Array[String] = Array(What's, up, doc?)
     
    scala> echo(arr)
    <console>:14: error: type mismatch;
     found   : Array[String]
     required: String
           echo(arr)
                ^
    

      

    要实现这个做法,需要在数组参数后添加一个冒号和一个_*,如下:

    scala> echo(arr:_*)
    What's
    up
    doc?
    

      

  • 相关阅读:
    SqlCacheDependency [转]
    C#导出Word [ZT]
    ADO.NET Entity Framework 学习(1) [ZT]
    AJAX, JSON.js,Newtonsoft.Json.dll,nunit.framework.dll 源代码
    ADO.NET 1.1和2.0事务的区别
    Sql Server 2000 中游标的使用示例 [ZT]
    如何检测是否安装了.NET 2.0和.NET 3.0 [ZT]
    ORACLE 常用函数 [ZT]
    Resource 学习笔记
    GridView 双击选择行 [ZT]
  • 原文地址:https://www.cnblogs.com/0205gt/p/10995881.html
Copyright © 2011-2022 走看看