• Scala基础入门-1


    首先需要Scala开发环境的搭建,网上自己找教程。

    声明常量与变量

    val foo = 0  // 常量
    var bar = 0  // 变量
    

      

    在Scala中,更加鼓励使用val来进行声明,也就是推荐使用常量。在大部分时候不需要分号,看自己便好…虽然是强静态类型的语言,但是却并没有写出类型——这就是类型推断。

    也可以指定类型:

    val spark: String = "Hello Scala"
    

      

    多个的同时声明:

    val xInt, yInt = 100  // xInt, yInt都声明为100
    

      

    常用类型

    与Java类似,Scala中也有表示数值类型的类,但是Scala不区分基本类型和引用类型。也就是说Scala中一切都是对象了吧。

    Scala对Java中的数值类型的功能添加了许多功能上的强化,这其中涉及了隐式转换。比如,String类型转换成StringOps类型。还有RichInt、RichDouble等对应Int、Double类型。至于有什么新加的方法,可以查看Scala API。

    操作符

    算数操作符应该与预期中的没有什么差异,因为如果有差异用起来就有麻烦了。但算数操作符事实上是方法。

    a + b  相当于  a.+(b)
    

    对于带有一个隐式参数和一个显式参数的方法来说,通常都可以这么简化。如:

    1.to(10)  这会产生一个1-10的Range实例,相当于  1 to 10
    

    两种风格任君选择。

    Scala没有提供++和–(别认为我打错了,这里是有两个-号的)这两个其他语言中很常见常用的操作符,理由是:不值得为少按一个键而额外增加一个特例。

    Scala中可以对操作符进行重载。

    调用函数和方法

    函数(function)和方法(method)

    引入相应的包后,使用函数很简单,不需要从某个类中调用静态方法。

    math.sqrt(2)  等同于  scala.math.sqrt(2)  // 以scala.开头的包名,都可以省去该前缀
    

      

    Scala中没有静态方法,但是有单例对象和伴生对象之类的概念可以实现差不多的特性,这些估计到后面会细说。

    BigInt.probablePrime(100, util.Random)
    

      

    通常,使用没有参数,且不改变当前对象的方法时,不带圆括号。

    apply方法

    s是一个字符串,而 s(4) 将会返回该字符串中第4个字符。在使用形如 s(4) 这种,类似于函数调用的语法时,实际上是调用了 apply() 方法。也就是说, s(4) 等于 s.apply(4)

    两个容易混淆的概念——表达式(expression)和语句(statement)。表达式有值,而语句没有值只执行操作。

    要说起这一点的原因是,Scala中,几乎所有构造出来的语法结构都有值,也就是表达式。这可以使程序更加精简易读。

    举例,if表达式是有值的;语句块也是有值的,是最后一个表达式的值。

    而对应Java中的void,Scala中有一个类型Unit,用来表示“无有用值”(void表示没有值,这里还是有差别的)。

    条件表达式

    if/else表达式在Scala中是有值的,除开这一点,与Java等语言没有什么差别。而有值所带来的效果,可以是下面这样子的:

    val s = if (x > 0) 1 else -1
    // 与上等效的另一种写法
    if (x > 0) s = 1 else s = -1
    

      

    第一种写法可以用来初始化一个val,而第二种则要求s必须是var。前面也说了,Scala中更鼓励使用val。

    同时,这样的条件表达式,还可以实现比三目操作符 ? : 更加灵活的功能。

    如果在if和else两边的类型是不同的,比如:

    if (x > 0) "positive" else -1
    

      

    这时返回的类型将会是两个分支类型的公共超类型(这里是String和Int的公共超类型Any)。

    如果没有else部分,那么if表达式有可能不返回值,这时候就需要前面提到的Unit类型,写做()。

    if (x > 0) 1
    // 这相当于else部分返回Unit类型,相当于下面的写法
    if (x > 0) 1 else ()
    

      

    语句终止

    分号不是必须的,但是使用它们不会带来坏处。

    能根据上下文判断出语句结尾的地方,都不需要使用分号。怎么判断是否语句结尾,以后在编码过程中会慢慢积累起感觉的。

    如果需要在单行中写多个语句,那么就需要使用分号了。而在写一个较长的语句时,如果需要分行写,要确保前面的行尾需要以不能用来语句结尾的符号来结束。比如说像是下面的操作符:

    a = s0 + (v - v0) * t + // +说明了这里不是语句结束哦
      0.5 + (a - a0) * t * t
    // 下面这种写法就会出问题了
    a = s0 + (v - v0) * t
      + 0.5 + (a - a0) * t * t
    

      

    这里还可以发现的是,Scala推荐使用两个空格来缩进。

    由于判断语句终止的需要,Scala程序员更倾向于使用Kernighan & Ritchie风格的花括号(也就是Java中推荐的方法):

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

      

    块表达式和赋值

    Scala中,{ }包含一系列的表达式,而且{ }最后返回的也是一个表达式——最后一个表达式。

    而赋值语句的值,是Unit类型的。这也大体上决定了在Java和C++中的 x = y = 1 会出现的赋值语句,几乎不可能出现在Scala中。

    输入和输出

    输入函数: readLine()、 readInt()等,用来从控制台Console中读取输入。

    而输出部分,则是很常见的 print()、 println()、 printf()。

    循环

    看看Scala中的for循环:

    for (i <- expression)  // 让i遍历表达式的所有值,遍历的执行取决于表达式的类型
    // 例子
    for (i <- 1 to n)  // 遍历1到n
    for (i <- 0 util s.length)  // 遍历0到s.length-1
    // 遍历求和
    var sum = 0
    for (ch <- "Hello") sum += ch
    

      

    事实上,Scala中更多是使用函数式而不是指令式的风格来遍历等操作。后面会见到的。

    高级for循环和for推导式

    在一个for循环中使用多个“generator”(生成器):

    for (i <- 1 to 3; j <- 1 to 3) print ((10 * i +j) + " "
    // 结果:11 12 13 21 22 23 31 32 33
    

      

    在for循环中使用“filter ”(过滤器,守卫)来过滤一部分不符合条件的枚举情况:

    for (i <- 1 to 3; j <- 1 to 3 if i != j) print ((10 * i + j) + " ")
    // 结果:12 13 21 23 31 32
    

      

    可以使用多个filter,中间需要使用分号分隔。

    可以在for表达式中使用任意多的定义,引入在循环中使用变量:

    for (i <- 1 to 3; from = 4 - i; j <- from to 3) print ((10 * i + j) + " ")
    // 结果:13 22 23 31 32 33
    

      

    如果for表达式的循环体是以yield关键词开始的,那么该循环会构造出一个集合,这被称为for推导式。推导式生成的集合与第一个generator是类型兼容的。

    for (c <- "Hello"; i <- 0 to 1) yield (c + i).toChar
    // 生成"HIeflmlmop"
    

      

    还可以将for表达式的小括号换成花括号,这样可以省去写分号的功夫。

    for表达式内容不少,而且这里也不是全部。在《Programming in Scala》中,还有一些高级的讨论,这里就先略了,先入个门。

    函数

    在Java中并没有函数这个概念,函数的功能是用静态方法来实现的。

    函数的定义:

    def 函数名(指明类型的参数): 可选的返回值类型 = 函数体
    def fac(n: Int) = {
      var r = 1
      for (i <- 1 to n) r = r * i
      r
    }
    

      

    只要函数不是递归的,就不需要给出函数的返回值类型(因为有类型推断)。一个递归的函数需要如下写:

    def fac(n: Int): Int = if (n <= 0) 1 else n * fac(n - 1)
    

      

    在Scala中,并不时常使用return来返回值。

    默认参数和带名参数

    Java里似乎没有默认参数和带名参数,至少我从来没有使用过。但记得C++是有的。

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

      

    上面的函数有两个带有默认值的参数left和right。如果不给出这两个参数,调用这个函数,会使用默认值。也可以给出自己的参数来替代默认的。

    参数个数不够时,将会从后往前使用默认参数。

    调用函数时,如果指定参数名,那么参数可以不按照参数列表的顺序来:

    decorate("Hello", right = "]<<<")

    从上面还可以知道,可以混用未命名参数和带名参数。

    变长参数

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

      

    星号表示可接受变长参数列表。函数实际得到的参数是Seq类型的。

    但是在调用变长参数函数时,并不能直接使用Seq类型的参数。要将一个Seq类型打散成单个的参数序列,使用 : _*。

    def recursiveSum(args: Int*) = {
      if (args.length == 0) 0
      else args.head + recursiveSum(args.tail: _*)
    }
    

      

    过程(procedure)

    过程的定义与函数很类似。函数体在花括号中,而且花括号前没有=号,返回值是Unit类型的,这就是过程了。(也可以写出=号,并且写明返回值是Unit类型来定义过程。)

    通常,过程没有返回值,只是为了副作用而调用一个过程。

    懒值

    当val被声明为lazy时,初始化会被推迟到首次对其取值时。

    lazy val words = io.Source.fromFile("/usr/share/dict/words").mkString
    

      

    如果程序一直不妨问words,那么Scala也不会去打开那个文件。文件是在实际第一次使用words时被打开的。

    懒值对开销较大的初始化语句十分有用,可以应对一些初始化问题比如循环依赖。还是开发懒数据结构的基础。

    可以将懒值当成是介于val和def的中间状态:

    • val在被定义时即被取值
    • lazy val在首次使用时被取值
    • def在每次使用时取值

    异常

    Scala中异常机制与Java和C++中一样。但Scala中并没有受检异常,也就是不需要说明函数方法可能会抛出什么异常。

    使用throw来抛出一个异常。throw表达式的类型是Nothing。

    捕获异常:

    try { 
      process(new URL("http://horstmann.com/fred-tiny.gif"))
    } catch {
      case _: => MalformedURLException => println("Bad URL: " + url)
      case ex: IOException => ex.printStackTrace()
    }
    

      

    如果不需要使用捕获的异常对象,使用_来代替变量名(_是Scala中的通配符)。

    同时也有try/finally语句,通常用来清理。可以组合成try/catch/finally语句

    fRom: http://nerd-is.in/2013-08/scala-learning-control-structures-and-functions/

      

      

  • 相关阅读:
    mpvue 引入 vant-weapp 踩坑记录
    mac上hbuilder无法启动微信小程序调试窗口的解决办法
    mac 安装了xcode,flutter doctor 却检测不到展示叉叉
    vue 前端复制粘贴方式上传图片
    401 错误时,几个细节检查
    vue 图片src动态加载
    前端优化的大方向
    how to stop code runner in vscode(macOs)
    window server 2008 r2 TLS 升级1.2
    超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小
  • 原文地址:https://www.cnblogs.com/spring87/p/4947871.html
Copyright © 2020-2023  润新知