• Scala学习(一)——基础语法


    Scala语言是一种面向对象语言,结合了命令式(imperative)和函数式(functional)编程风格,其设计理念是创造一种更好地支持组件的语言。

    特性

    • 多范式(Multi-Paradigm)编程语言,类似Java、C#;

    • 继承面向对象编程和函数式编程的特性;

      • 面向对象:[1]. 子类继承,[2]. 混入(Mixin)机制;

      • 函数式:支持高阶函数、嵌套函数,模式匹配,支持柯里化(Currying);

      • 类型推断(Type Inference):根据函数体中的具体内容推断方法的返回值类型

    • 更高层的并发模型,可伸缩;

    • 静态类型,编译时检查;

    • 允许与Java互操作(将来会支持与.Net互操作);

    与Java对比

    • 如果用作服务器端开发,Scala的简洁、灵活性是Java无法比拟的;

    • 如果是企业级应用开发、Web开发,Java的强大是Scala无法匹敌的;

    基础语法

    表达式(Expressions)

    表达式是可计算的语句。您可以使用println输出表达式的结果。

    println(1) // 1
    println(1 + 1) // 2
    println("Hello!") // Hello!
    println("Hello," + " world!") // Hello, world!

    值(Values)

    您可以使用val关键字命名表达式的结果。

    val x = 1 + 1
    println(x) // 2

    命名结果(例如x)称为值。引用值不会重新计算它。值无法被重新分配。

    val x = 1 + 1
    x = 3 // This does not compile.

    可以推断出值的类型,但您也可以显式声明类型,如下所示:

    val x: Int = 1 + 1

    注意类型声明Int如何在标识符x之后出现,你还需要一个“:”

    变量(Variables)

    变量就像值,除了你可以重新赋值。您可以使用var关键字定义变量。

    var x = 1 + 1
    x = 3 // This compiles because "x" is declared with the "var" keyword.
    println(x * x) // 9

    与值一样,您可以根据需要明确说明类型:

    var x: Int = 1 + 1

    块(Blocks)

    您可以通过用{}包围表达式来组合表达式。我们称之为块。块中最后一个表达式的结果也是整个块的结果。

    println({
      val x = 1 + 1
      x + 1
    }) // 3

    函数(Functions)

    函数是带参数的表达式。

    您可以定义一个返回给定整数加一的匿名函数(即无名称):

    (x: Int) => x + 1

    在=>的左边是参数列表。右边是涉及参数的表达式。

    您也可以命名函数。

    val addOne = (x: Int) => x + 1
    println(addOne(1)) // 2

    函数可能需要多个参数。

    val add = (x: Int, y: Int) => x + y
    println(add(1, 2)) // 3

    或者它不需要参数。

    val getTheAnswer = () => 42
    println(getTheAnswer()) // 42

    方法(Methods)

    方法的外观和行为与函数非常相似,但它们之间存在一些关键差异。

    方法使用def关键字定义。 def后跟名称,参数列表,返回类型和正文。

    def add(x: Int, y: Int): Int = x + y
    println(add(1, 2)) // 3

    注意如何在参数列表和冒号之后声明返回类型:Int。

    方法可以采用多个参数列表。

    def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
    println(addThenMultiply(1, 2)(3)) // 9

    或者根本没有参数列表。

    def name: String = System.getProperty("user.name")
    println("Hello, " + name + "!")

    还有一些其他差异,但就目前而言,您可以将它们视为与函数类似的东西。

    方法也可以有多行表达式。

    def getSquareString(input: Double): String = {
      val square = input * input
      square.toString
    }

    正文中的最后一个表达式是方法的返回值。 (Scala确实有一个return关键字,但它很少使用。)

    关于方法(Method)和函数(Function)

    • 函数是一等公民,使用val语句可以定义函数,def语句定义方法;

    • 函数是一个对象,继承自FuctionN,函数对象有curried,equals,isInstanceOf,toString等方法,而方法不具有;

    • 函数是一个值,可以给val变量赋值,方法不是值、也不可以给val变量赋值;

    • 通过将方法转化为函数的方式 method _ 或 method(_) 实现给val变量赋值;

    • 若 method 有重载的情况,方法转化为函数时必须指定参数和返回值的类型;

    • 某些情况下,编译器可以根据上下文自动将方法转换为函数;

    • 无参数的方法 method 没有参数列表(调用:method),无参数的函数 function 有空列表(调用:function());

    • 方法可以使用参数序列,转换为函数后,必须用 Seq 包装参数序列;

    • 方法支持默认参数,函数不支持、会忽略之;

    类(Classes)

    您可以使用class关键字定义类,后跟其名称和构造函数参数。

    class Greeter(prefix: String, suffix: String) {
      def greet(name: String): Unit =
        println(prefix + name + suffix)
    }

    方法greet的返回类型是Unit,它表示返回没有任何意义。它与Java和C中的void类似地使用。(不同之处在于,因为每个Scala表达式必须具有某个值,实际上存在Unit类型的单例值,write()。它不携带任何信息。)

    您可以使用new关键字创建类的实例。

    val greeter = new Greeter("Hello, ", "!")
    greeter.greet("Scala developer") // Hello, Scala developer!

    样本类(Case Classes)

    Scala有一种特殊类型的类,称为样本类。默认情况下,样本类是不可变的,并按值进行比较。您可以使用“case class”关键字定义案例类。

    case class Point(x: Int, y: Int)

    您可以在没有new关键字的情况下实例化样本类。

    val point = Point(1, 2)
    val anotherPoint = Point(1, 2)
    val yetAnotherPoint = Point(2, 2)

    并且它们按值进行比较。

    if (point == anotherPoint) {
      println(point + " and " + anotherPoint + " are the same.")
    } else {
      println(point + " and " + anotherPoint + " are different.")
    }
    // Point(1,2) and Point(1,2) are the same.
    if (point == yetAnotherPoint) {
      println(point + " and " + yetAnotherPoint + " are the same.")
    } else {
      println(point + " and " + yetAnotherPoint + " are different.")
    }
    // Point(1,2) and Point(2,2) are different.

    对象(Objects)

    对象是它们自己定义的单个实例。你可以把它们想象成自己班级的单身人士。

    您可以使用object关键字定义对象。

    object IdFactory {
      private var counter = 0
      def create(): Int = {
        counter += 1
        counter
      }
    }

    您可以通过引用其名称来访问该对象。

    val newId: Int = IdFactory.create()
    println(newId) // 1
    val newerId: Int = IdFactory.create()
    println(newerId) // 2

    抽象类

    你可以定义一个抽象类,它定义了一些方法但没有实现它们。取而代之是由扩展抽象类的子类定义这些方法。你不能创建抽象类的实例。

    abstract class Shape {      
      def getArea():Int    // subclass should define this      
    } 
    class Circle(r: Int) extends Shape {      
      def getArea():Int = { r * r * 3 }      
    } 
    val s = new Shape //error: class Shape is abstract; cannot be instantiated                     
    val c = new Circle(2)

    特质(Traits)

    特质是包含某些字段和方法的类型。可以组合多种特质。
    您可以使用trait关键字定义特质。

    trait Greeter {
      def greet(name: String): Unit
    }

    特质也可以有默认实现。

    trait Greeter {
      def greet(name: String): Unit =
        println("Hello, " + name + "!")
    }

    您可以使用extends关键字扩展traits并使用override关键字覆盖实现。

    class DefaultGreeter extends Greeter
    class CustomizableGreeter(prefix: String, postfix: String) extends Greeter {
      override def greet(name: String): Unit = {
        println(prefix + name + postfix)
      }
    }
    val greeter = new DefaultGreeter()
    greeter.greet("Scala developer") // Hello, Scala developer!
    val customGreeter = new CustomizableGreeter("How are you, ", "?")
    customGreeter.greet("Scala developer") // How are you, Scala developer?

    在这里,DefaultGreeter只扩展了一个特质,但它可以扩展多个特质。

    什么时候应该使用特质而不是抽象类?

    如果你想定义一个类似接口的类型,你可能会在特质和抽象类之间难以取舍。这两种形式都可以让你定义一个类型的一些行为,并要求继承者定义一些其他行为。一些经验法则:

    • 优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。

    • 如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行。例如,你不能说trait t(i: Int) {},参数i是非法的。

    Main方法

    Main方法是程序的切入点。 Java虚拟机需要将main方法命名为main,并使用一个参数,即一个字符串数组。
    使用对象,您可以按如下方式定义main方法:

    object Main {
      def main(args: Array[String]): Unit =
        println("Hello, Scala developer!")
    }

    本文主要翻译自Basics|Scala Documentation

  • 相关阅读:
    echarts onClick执行之前都要取消绑定一次
    echarts 打包完之后体积太大解决方案。
    saga处理多个loading最少0.5s
    SVN命令详解
    netfilter/iptables原理
    交换两个变量的值,不使用第三个变量的四种法方
    linux常用命令整理
    vi技巧
    linux进程管理的常用命令
    gcc常用命令
  • 原文地址:https://www.cnblogs.com/wmx24/p/9362697.html
Copyright © 2020-2023  润新知