Scala初识02

对象和类

在同一个object中如果有两个main方法,可以自己选择运行哪个方法

object ObjectAndClass {
  def main(args: Array[String]): Unit = {
    val num = 11;
    println(num)
  }
}

object Class {
  def main(args: Array[String]): Unit = {
    println("hello from class")
  }
}

在object中,代码可以写在方法外面,而java中不可以,暂时可以理解为类似于java中的静态代码块,但是这种说法是不准确的

这种代码是相当于直接在默认构造器中的,有默认构造器,人无需关心

所以作为人关心的应该是个性化构造

类名构造器中的参数就是类的成员属性且默认是private的val类型

类名构造器和个性化构造器会产生冲突

package objectandclass

/**
  * @Author: mio
  * @Date: 2019/10/9 8:43
  */
object ObjectAndClass {
  def main(args: Array[String]): Unit = {
    val vtuber = new vtb(14)
    vtuber.speak();
  }
}

class vtb(sex: String) {
  var name = "hololive default name"

  def this(name: Int) {
    //    这里必须调用默认构造
    this(name.toString)
    //    this.name = name.toString
  }

  println("i'm from hololive")

  def speak(): Unit = {
    println(s"i'm $name and i'm a $sex")
  }

  println("i'm a gamer")
}

if,while和for

if else和java没有太大区别

package if_while_for

object Main {
  def main(args: Array[String]): Unit = {
    val age = 14;
    if (age > 0) println(s"$age > 0")
    else if (age < 0) println(s"$age < 0")
    else println(s"$age = 0")
  }
}

while也很简单,只不过没有++和–等,取而代之换成了-=和+=

package if_while_for

object Main {
  def main(args: Array[String]): Unit = {
    while (age > 0) {
      println(age)
      age -= 1
    }
  }
}

scala中没有步进for循环,只有迭代型循环,这是一种步进型写法

package if_while_for

object Main {
  def main(args: Array[String]): Unit = {
    val inclusive: Range.Inclusive = 1 to (10,2)
    println(inclusive)
  }
}

边界及守卫

//    包含边界
val inclusive: Range.Inclusive = 1 to(10, 2)
println(inclusive)

//    不包含
val range: Range = 1 until (10)
println(range)

for (i <- range) {
    println(i)
}

println("守卫")

//    守卫
for (i <- range if (i % 2 == 0)) {
    println(i)
}

九九乘法表的练习

//    九九乘法表练习
for (i <- 1 to 9) {
    for (j <- 1 to 9) {
        if (j <= i) print(s"$i * $j = ${i * j}\t")
        if (j == i) println()
    }
}
var num = 0;
//    代码改良
for (i <- 1 to 9; j <- 1 to 9) {
    if (j <= i) print(s"$i * $j = ${i * j}\t")
    if (j == i) println()
    num += 1
}
println(num)
//    代码继续改良,加入守卫,限制循环次数,节省时间提升性能
num = 0
for (i <- 1 to 9; j <- 1 to 9 if (j <= i)) {
    if (j <= i) print(s"$i * $j = ${i * j}\t")
    if (j == i) println()
    num += 1
}
println(num)

yield关键字

for循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。Scala中for循环是有返回值的。如果被循环的是Map,返回的就是Map,被循环的是List,返回的就是List,以此类推。

val seqss: immutable.IndexedSeq[Int] = for (i <- 1 to 10) yield {
    i
}
println(seqss)

method和function

//    method和function
def vtuber(): Unit = {
    println("hello hololive!")
}

val unit = vtuber()
println(unit)

有return必须手动给出返回值类型,没有return编译器会自动帮你确定返回类型

object Main {
  def main(args: Array[String]): Unit = {
    def hololive()={
      14
    }
    println(hololive())
  }
}

递归需要明确给出返回值类型

object Main {
  def main(args: Array[String]): Unit = {
    def hololive(num: Int):Int = {
      if (num == 1) {
        num
      } else {
        num * hololive(num - 1)
      }
    }
    println(hololive(5))
  }
}

默认值函数

object Main {
  def main(args: Array[String]): Unit = {
    def hololive(aqua: Int = 14, mea: Int = 15) = {
      println(aqua + mea)
    }
//    hololive()
//    hololive(16,17)
    hololive(mea = 18)
  }
}

匿名函数的类型(函数的签名,也就是(参数类型列表)=>返回值类型,参考(Int, Int) => Int)

object Main {
  def main(args: Array[String]): Unit = {
    val function: (Int, Int) => Int = (aqua: Int, mea: Int) => {
      aqua + mea
    }
    println(function(3,4))
  }
}

嵌套函数

object Main {
  def main(args: Array[String]): Unit = {
    def hololive(a:String)={
      def vtuber()={
        println(a)
      }
      vtuber()
    }

    hololive("aqua")
  }
}

偏应用函数

import java.util.Date

object Main {
  def main(args: Array[String]): Unit = {
    def hololive(date: java.util.Date, tp: String, message: String): Unit = {
      println(s"$date,$tp,$message")
    }

    hololive(new java.util.Date(), "info", "message")

    val info = hololive(_: java.util.Date, "info", _: String)
    val error = hololive(_: Date, "error", _: String)
    info(new java.util.Date(), "message")
    error(new java.util.Date(), "message")
  }
}

可变参数列表,要求参数的类型一致

object Main {
  def main(args: Array[String]): Unit = {
    def hololive(aqua: Int*): Unit = {

      //      for (element <- aqua) println(element)

      //      aqua.foreach((x: Int) => {
      //        println(x)
      //      })

      //      aqua.foreach(println(_))

      aqua.foreach(println)
    }

    hololive(1, 2, 3, 4, 5)
  }
}

高阶函数,在函数体中如果参数列表的参数按顺序依次出现在函数体中,可以省略参数列表并且将参数全部换成下划线

object Main {
  def main(args: Array[String]): Unit = {
    def compare(aqua: Int, mea: Int, f: (Int, Int) => Int): Unit = {
      val result: Int = f(aqua, mea)
      println(result)
    }

    compare(3, 8, (x: Int, y: Int) => {
      x + y
    })

    compare(3, 8, _ + _)

    compare(3, 8, (x: Int, y: Int) => {
      x * y
    })

    compare(3, 8, _ * _)
  }
}
object Main {
  def main(args: Array[String]): Unit = {
    def compare(aqua: Int, mea: Int, f: (Int, Int) => Int): Unit = {
      val result: Int = f(aqua, mea)
      println(result)
    }

    def factory(i: String): (Int, Int) => Int = {
      def plus(x: Int, y: Int): Int = {
        x + y
      }

      if (i.equals("+")) {
        plus
      } else {
        (x: Int, y: Int) => {
          x * y
        }
      }
    }

    compare(3, 8, factory("*"))
  }
}

柯里化

object Main {
  def main(args: Array[String]): Unit = {
    def hololive(mea: Int)(aqua: Int)(alice: String) = {
      println(s"$mea,$aqua,$alice")
    }

    hololive(2)(1)("alice")

    def vtuber(a: Int*)(b: String*): Unit = {
      a.foreach(println)
      b.foreach(println(_))
    }

    vtuber(1,2)("alice")
  }
}

官网参考资料

在Scala中,所有的值都有类型,包括数值和函数。下图阐述了类型层次结构的一个子集。

scala中值的类型

Scala类型层次结构

Any是所有类型的超类型,也称为顶级类 型。它定义了一些通用的方法如equalshashCodetoStringAny有两个直接子类:AnyValAnyRef

AnyVal代表值类型。有9个预定义的非空的值类型分别是:DoubleFloatLongIntShortByteCharUnitBooleanUnit是不带任何意义的值类型,它仅有一个实例可以像这样声明:()。所有的函数必须有返回,所以说有时候Unit也是有用的返回类型。

AnyRef代表引用类型。所有非值类型都被定义为引用类型。在Scala中,每个用户自定义的类型都是AnyRef的子类型。如果Scala被应用在Java的运行环境中,AnyRef相当于java.lang.Object

这里有一个例子,说明了字符串、整型、布尔值和函数都是对象,这一点和其他对象一样:

val list: List[Any] = List(
  "a string",
  732,  // an integer
  'c',  // a character
  true, // a boolean value
  () => "an anonymous function returning a string"
)

list.foreach(element => println(element))

这里定义了一个类型List<Any>的变量list。这个列表里由多种类型进行初始化,但是它们都是scala.Any的实例,所以可以把它们加入到列表中。

下面是程序的输出:

a string
732
c
true
<function>

类型转换

值类型可以按照下面的方向进行转换:

Scala Type Hierarchy

例如:

val x: Long = 987654321
val y: Float = x  // 9.8765434E8 (note that some precision is lost in this case)

val face: Char = '☺'
val number: Int = face  // 9786

转换是单向,下面这样写将不会通过编译。

val x: Long = 987654321
val y: Float = x  // 9.8765434E8
val z: Long = y  // Does not conform

你可以将一个类型转换为子类型,这点将在后面的文章介绍。

Nothing和Null

Nothing是所有类型的子类型,也称为底部类型。没有一个值是Nothing类型的。它的用途之一是给出非正常终止的信号,如抛出异常、程序退出或者一个无限循环(可以理解为它是一个不对值进行定义的表达式的类型,或者是一个不能正常返回的方法)。

Null是所有引用类型的子类型(即AnyRef的任意子类型)。它有一个单例值由关键字null所定义。Null主要是使得Scala满足和其他JVM语言的互操作性,但是几乎不应该在Scala代码中使用。我们将在后面的章节中介绍null的替代方案。