首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

关于Scala 这是最基础的知识了

Scala是一门多范式的编程语言,一种类似java的编程语言,设计初衷是实现可伸缩的语言 、并集成面向对象编程和函数式编程的各种特性。

什么是静态类型?为什么它们很有用?

根据Picrce的说法:“类型系统是一个可以根据代码段计算出来的值对它们进行分类,然后通过语法的手段来自动检测程序错误的系统。”

类型可以让你表示函数的域和值域。例如,在数学里,我们经常看到下面的函数:

这个定义告诉我们函数”f”的作用是把实数集里的数映射到自然集里。

抽象地说,这才是具体意义上的类型。类型系统给了我们一些表示这些集合的更强大的方式。

有了这些类型标识,编译器现在可以静态地(在编译期)判断这个程序是正确的。换句话说,如果一个值(在运行期)不能够满足程序里的限制条件的话,那么在编译期就会出错。

通常来说,类型检测器(typechecker)只能够保证不正确的的程序不能通过编译。但是,它不能够保证所有正确的程序都能通过编译。

由于类型系统的表达能力不断增加,使得我们能够生成出更加可靠的代码,因为它使得我们能够控制程序上的不可变,即是是程序还没有运行的情况下(在类型上限制bug的出现)。学术界一直在努力突破类型系统的表达能力的极限,包含值相关的类型。

注意,所有的类型信息都会在编译期擦除。后面不再需要。这个被称为类型擦除。

Scala中的类型

Scala强大的类型系统让我们可以使用更具有表现力的表达式。一些主要的特点如下:

支持参数多态,泛型编程

支持(局部)类型推导,这就是你为什么不需要写

val i: Int = 12: Int

支持存在向量(existential quantification),给一些没有名称的类型定义一些操作

支持视图。 我们下个星期再讨论;给定的值从一个类型到其他类型的“可转换性”

参数多态

多态可以用来编写泛型代码(用于处理不同类型的值),并且不会减少静态类型的表达能力。

例如,没有参数多态的话,一个泛型的列表数据结构通常会是下面这样的写法(在Java还没有泛型的时候,确实是这样的):

这样的话,我们就不能够恢复每个元素的类型信息。

这样一来,我们的应用里会包含一系列的类型转换(“asInstanceOf[]“),代码会缺少类型安全(因为他们都是动态类型的)。

多态是通过指定类型变量来达到的。

多态是scala里的一等公民

简单来说,这意味着有一些你想在Scala里表达的类型概念会显得“太过于泛型”,从而导致编译器无法理解。假如你有这样一个函数:

你想要按照泛型的方式来使用它:

但是这样会编译不过,因为所有的类型变量在运行期必须是确定的。

…you get a type mismatch.

…你会看到一个类型不匹配的错误

类型推导

对于静态类型的一个比较常见的缺陷就是有太多的类型语法。Scala提供了类型推导来解决这个问题。

函数式语言里比较经典的类型推导的方法是 Hindlry-Milner,并且它是在ML里首先使用的。

Scala的类型推导有一点点不同,不过思想上是一致的:推导所有的约束条件,然后统一到一个类型上。

在Scala里,例如,你不能这样写:

但是在OCaml里,你可以:

在Scala里,所有的类型推导都是局部的。Scala一次只考虑一个表达式。例如:

在这里,类型都被隐藏了。Scala编译器自动推导参数的类型。注意我们也没有必要显示指定返回值的类型了。

Varicace

Scala的类型系统需要把类的继承关系和多态结合起来。类的继承使得类之间存在父子的关系。当把面向对象和多态结合在一起时,一个核心的问题就出来了:如果T'是T的子类,那么Container[T']是不是Container[T]的子类呢?Variance注释允许你在类继承和多态类型之间表达下面的这些关系:

子类关系的真正意思是:对于一个给定的类型T,如果T’是它的子类,那么T’可以代替T吗?

逆变(Contravariance)看起来比较奇怪。什么时候要用到它呢?确实让人感到惊讶!

如果你从替代的角度来看这个的话,非常容易理解这一点。我们首先来定义一个简单的类继承关系:

假设你需要一个接收

Bird

类型参数的函数:

标准的animal类库有一个函数可以完成你想要的任务,但是它的参数是

Animal

。在大部分的场景下,如果你说“我需要一个,我有一个的子类”,这样是可以的。但是函数的参数都是可逆变的(contravariant),如果你需要一个接受一个

Bird

的函数,并且你有一个接收一个

Chicken

的函数,这个函数会卡在

Duck

上。但是一个接收

Animal

作为参数的函数就没有问题:

函数的返回值是可逆变的。如果你需要一个返回

Bird

的函数,但是你只有一个返回

Chicken

的函数,这样也是可以的。

范围(Bounds)

Scala允许你通过 bounds 来限制多态的范围。这些范围表示的是子类的关系。

还可以支持更低的类型范围;它们可以通过逆变(contravariance)和合适的协变(covariance)来实现。

List[+T]

是协变量;一个Bird的列表同时也是一个Animal的列表。

List

定义了一个操作符

::[elem T]

返回一个装载

elem

的列表。这个新的

List

和原来的列表有着相同的类型:

List

同时 也定义了

::[B >: T]

,它返回一个

List[B]

。注意

,它表示

T

的父类。这个会在我们把一个

Animal

添加到一个

List[Bird]

的时候提醒我们进行纠正。

注意返回的类型是

Animal

量化(Quantification)

有时候你不需要给一个类型变量以名称,例如

你可以用“通配符”来替代:

这个可以替代:

注意量化(quantification)可能会显得比较诡异:

突然之间我们丢失了类型信息!为了一探究竟,我们来看看最原始的语法:

我们不能说明T的任何信息,因为在这里的类型不允许。

你也可以对通配符类型使用范围来进行限定:

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180125A04AMJ00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券