for input string: 5 _《Scala实用指南》读书笔记5

第五章:善用类型

1.类型推断

跟Golang一样,变量定义都是 变量名在前,类型在后

// golang
var path String

java 都是:String path 这样的,scala:

val path:String = "hello"

在Java中是先指定变量的类型,然后是变量名,而在Scala中,恰好做了相反的操作,为什么这样做

  • scala暗示 变量名比标注类型更加重要
  • 类型信息是可选的

推荐使用类型推断,这样会更加简洁:val path = "hello"

在以下几种情况下,必须要显式地指定类型:

  • 当定义没有初始值的类字段时;
  • 当定义函数或方法的参数时;
  • 当定义函数或方法的返回类型,仅当我们使用显式的return语句或者使用递归时[1];
  • 当将变量定义为另一种类型,而不是被直接推断出的类型时,如val frequency: Double = 1

针对泛型和集合的类型推断

package chapter5
​
import java._
​
object DefiningVariableWithType extends App {
  // Java ArrayList类型
  var list1:util.List[Int] = new util.ArrayList[Int]()
  var list2 = new util.ArrayList[Int]()
  var list3 = new util.ArrayList
​
  // print: class java.util.ArrayList
  println(list1.getClass)
​
  // OK
  list1 = list2
​
  // error, list3 as ArrayList[Nothing]
  // list2 = list3
​
}

在Scala中,Nothing是所有类型的子类型。通过将new ArrayList的结果看作是一个ArrayList[Nothing]的实例

Any是所有类型的基础类型

Scala认为,没有指定参数化类型的集合是元素类型为 Nothing的集合,并限制了跨类型的赋值。

如下:

  var list1 = new util.ArrayList[Int]()
  var list2 = new util.ArrayList[Any]()
​
  var ref1:Int = 1
  var ref2:Any = _
​
  // 把ref2赋值给ref1编译错误
  // ref1 = ref2
​
  // 把ref1赋值给ref2编译通过
  // 等效于在Java中将一个指向Integer的引用赋值给一个类型为Object的引用
  ref2 = ref1
​
  // 然而在默认的情况下,Scala不允许将一个元素类型为任意类型的集合赋值给一个指向元素类型为Any的集合的引用
  // 如list1赋值list2就会失败
  // 把list2赋值给list1编译失败, 把list1赋值给list2也会编译失败
  //list1 = list2
  //list2 = list1

2.基础类型

将学到:

  1. Any类型
  2. Nothing类型
  3. Option类型
  4. Either类型

2.1 Any类型

52074652b952390e90946630ad28b1bc.png

Any:

  • 是所有类型的超类型
  • 可以作为任意类型对象的一个通用引用
  • 是一个抽象类
  • 直接后裔是AnyValAnyRef类型

2.2 Nothing类型

书中讲的Nothing,确实没有领会到具体用处,貌似是一个纯粹的辅助类型,用于类型推断以及类型验证

1b1637a56479e564f4230458d63e92b7.png
Any类型是所有类型的父类型,而 Nothing则是一切类型的子类型。

2.3 Option类型

当一个函数调用的结果可能存在也可能不存在时, Option类型很有用

Option类型可以让你更好的避免Null带来的影响,如空指针

def demo(input:String) = {
    if (input == "test") Some("good") else None
  }
​
for(input <- Set("test", "good")) {
    val v = demo(input)
    val vv = v.getOrElse("None....")
    println(vv)
}

上面方法返回的是Some[T]的实例或者None,而不是String的实例。这两个类都继承自Option[T]类。接受Option[T]实例的代码将会获取结果,并明确地预期结果可能并不存在(getOrElse())来更好的处理

如果在Java中我们可能就(if xx == null) 来做一大堆限制,否则就NullPointerException

2.4 Either类型

用于从一个函数中返回两种不同类型的值之一,Either类型有两种值:

  • Left:错误的
  • Right:期望的
scala> def compute(input:Int) = { if(input > 0) Right(input * 2) else Left("invalid input") }
compute: (input: Int)Product with Serializable with scala.util.Either[String,Int]
当接收到一个 Either类型的值时,可以使用模式匹配来提取其中的值
def show(result:Either[String, Int]) = {
    println(s"Raw: $result")
    result match {
      case Right(value) => println(s"result: $value")
      case Left(err) => println(s"Error: $err")
    }
  }
​
show(compute(100))
show(compute(-100))
​
// output:
Raw: Right(200)
result: 200
Raw: Left(invalid input)
Error: invalid input

3.返回值类型推断

在Scala中,在函数声明和它的主体之间使用等号( =)是理想的惯用风格——即使对于返回 Unit的方法来说也是如此。
Unit类似Java void
只有当你使用等号( =)将方法的声明和方法的主体部分区分开时,Scala的返回值类型推断才会生效。否则,该方法将会被视为返回一个 Unit
scala> def f1 {Math.sqrt(2)}
f1: Unit
​
scala> def f2 = {Math.sqrt(2)}
f2: Double
​
// 主体是一个简单表达式或者复合表达式可省略花括号
scala> def f3 = Math.sqrt(2)
f3: Double
​
scala> def f4:Double = Math.sqrt(2)
f4: Double
​
// 指定返回值类型,那么它必须要和方法主体的最后一个表达式产生的结果类型兼容, 否则报错
scala> def f4:String = Math.sqrt(2)
<console>:11: error: type mismatch;
 found   : Double
 required: String
       def f4:String = Math.sqrt(2)

4.参数化类型的型变

TODO

4.1 协变和逆变

一个Java的例子

package chapter5;
​
class Fruit {}
class Banana extends Fruit {}
class Apple extends Fruit {}
​
public class Trouble {
    public static void main(String[] args) {
        // 香蕉箱,要放2个香蕉
        Banana[] bananaBox = new Banana[2];
        // 放一个香蕉
        bananaBox[0] = new Banana();
​
        // 水果箱,由于香蕉也是水果,所以可以把香蕉箱赋给水果箱, 此时水果箱已经有一个香蕉了
        Fruit[] fruitBox = bananaBox;
        // 在水果箱放一个苹果
        // 这里会报错:Exception in thread "main" java.lang.ArrayStoreException: chapter5.Apple
        fruitBox[1] = new Apple();
​
        // 打印香蕉
        for (Banana banana: bananaBox) {
            System.out.println(banana);
        }
    }
}

上面代码编译没错,但运行就是报错,发生错误的原因是,在运行时,我们以使用一篮子水果为托词,试图把一个苹果放到一篮子香蕉中,但是呢Java编译器却没有报错

书上写的太晦涩,还是参考:Scala中的协变,逆变,上界,下界等

5.隐式类型转换

TODO

6.值类

TODO

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值