文档章节

[译] 印度朋友手把手教你学Scala(2):Scala里的类型推断 & 类型

暗夜在火星
 暗夜在火星
发布于 2017/02/26 12:43
字数 2752
阅读 21
收藏 0
点赞 0
评论 0
/**
 * 谨献给我最爱的YoYo
 * 原文出处:https://madusudanan.com/blog/scala-tutorials-part-2-type-inference-in-scala/
 * @author dogstar.huang <chanzonghuang@gmail.com> 2017-02-25
 */

本翻译已征得Madusudanan.B.N同意,并链接在原文教程前面。

类型推断

这是关于Scala系列教程的第二章。点击这里可查看整个系列。

如果你还记得的话,在上一章,我们通过一些示例简短地讲解了推断推断。现在我们准备通过更多的示例继续进行深挖,以下是这篇文章的主要内容。

温馨提示:这是一个枯燥无味的主题,很多都是基本的理论,但也很重要。我已经努力尽可能以最简约覆盖本质的内容。此外,提供了很多材料以供业余学习。

目录

  • 从程序员的视角,到底什么是类型推断
  • 类型系统概览
  • 根据类型系统的语言分类
  • 类型推导器(HM)类型推断
  • 本地 vs 全局类型推断 -- 为什么Scala选择本地推断推断
  • Scala类型系统和子类型的简单介绍
  • 何时使用类型推断
  • 参考

从程序员的视角,到底什么是接口类型

对于Scala来说,这没什么特别。很多语言,例如OCaml,Haskell,Rust,Swift,C#(3.0版本开始) 都已经有这些了。

先从维基百科的定义开始。

类型推论、类型推断、或隐含类型,是指编程语言在编译期中能够自动推导出值的数据类型的能力,它是一些强静态类型语言的特性。

好吧,就像我们在上一篇文章看到的那样,很明显它会自动推断类型。

早期的目的是为了帮助程序员避免啰嗦的输入但仍然可以维护静态类型语言编译时的类型安全。

简单来说,类型推断是静态类型和动态类型这两个世界里最好的。

或者至少它尽力成为这样。实际上很大程度上取决于我们在哪里/如何使用它。

类型系统概览

类型系统是一个负责类型检查的语言容器。Scala是静态类型语言,所以通常会有一系列类型,而任何不在那个系列里的东西都会被视为非法类型,并且会抛出一个编译时错误。

为什么一点也不容纳任何其他类型系统呢?

因为计算机匹配不了人类的失误,而既定的东西更容易被计算机处理,而不是依靠人来把它给调整正确。它也可以防止由于合适类型而冒出的一大堆Bug。类型系统存在是为了提供类型安全,而不同的语言和不同的运行时,有不同的严格级别。

这把我们带到了另外一个问题,存在哪些类型系统,以及根据哪一个我们可以区别不同的语言。

根据类型系统的语言分类

引自这篇维基百科的页面

  • 动态检查
  • 静态检查
  • 显示宣告和隐式暗示(Inferred vs Manifest)
  • 标明类型系统和结构类型系统(Nominal vs Structural)
  • 依存类型(Dependant typing)
  • Gradual typing
  • Latent typing
  • 子类型
  • Uniqueness typing
  • 强类型和弱类型

译者注:更多从维基百科页面引用过来的类型如下。

  • 复合类型
  • 派生类型
  • 对象类型
  • 不完全类型
  • 递归类型
  • 函数类型
  • 全称量化类型
  • 存在量化类型
  • 精炼类型
  • 所有权类型

这么多系统,看得都让人头晕。我也非常推荐你听下这门课程,以便了解理多。视频可以下载/离线观看。

这可能也会出现在[course]https://www.coursera.org/course/proglang)上,所以确保你把它添加到了你的待看列表里。

这里还有另一个相当好的课程

综上所述,Scala可以分类成一门带类型推断的静态类型语言。函数式编程和类型推断之间有很强的关系,后面我们还会一次又一次讲到。

类型推导器(HM)类型推断

关于类型推断,我们可以谈论好几天,但最著名的算法应该当数HM类型推断算法

HM算法检查程序从而推断出它属于什么类型。如果你已经听完了上面的课程,那么对于这意味着什么就会有一个相当明朗的概念。

以下是一个典型带类型推断的类型系统是如何工作的例子。它会构建一棵包含全部元素的解析树,分析全部元素可能属于的类型,并且达到一个最终结论。 

以上示例是伪代码,语法并不重要。如果总和小于10则返回true,否则大于等于10则返回false。我们可以从这个示例翻译/构建成另一个复杂的工作流。

很多算法几乎都是以相同的方式工作。如果有类似把两个字符串相乘的任何错误,它会抛出一个异常。

一些入门级的Haskell编程真的会有助于更好地理解这一点。Learn you a haskell是一个很好的入门网站。

Hindley-Milner算法也被称为全局类型推断。它读取整段代码并且推断类型。Scala类型系统的工作方式和上面解释的有一点不同。

本地 vs 全局类型推断 -- 为什么Scala选择本地类型推断

Scala遵循子类型和本地类型推断的结合。我打算把它和Haskell比较,因为它是最出名的函数式编程(FP)范式语言之一。

让我们通过另外一个示例来加深理解。

考虑以下代码,在Intellij里会产生一个编译时错误。

def factorial(a: Int) = {  
    if (a <= 1) 1 else a * factorial(a - 1)
}

错误信息如下: 

现在可先忽略语法细节(当学习方法时我们会更深入进行讲解)。这段程序会计算传入数字的阶乘。如果我们看到了这些错误,说明预编译器不能推断出递归函数返回的类型。相同(类似)的Haskell代码则没有任何错误。

let factorial 0 = 1; factorial n = n * factorial (n - 1)  

当在Haskell GHCI(类似Scala的REPL)里执行上面代码,无编译错误。 

这是现实世界一个全局和本地类型推断的例子。在Scala,本地类型推断帮助不了的地方我们都不得不标注类型(也请参考下面的:何时使用类型推断)。

上面代码的正确版本应许如下。注意在上面代码中没出现的Int类型在这里被明确指定了。

def factorial(a:Int): Int = {  
    if(a <=1) 1 else a * factorial(a-1)
}  

对于多范式语言,全局/类型推导真的真的很难,因为受限于例如继承和方法重载这些OOP特性。我们不打算过多地深究为什么像Haskell这样的语言做不到这些事情(如果你对系统编程/编译器黑客感兴趣,在网上有很多很多资源),但重点是Scala做了一个不同的交易。

Scala类型系统和子类型的简单介绍

如上所述,类型系统是由预定义的类型组件构成,并且这形成了scala如何继承的基础。 

一图胜千言,你可以尝试使用一般IDE的“ctrl + 单击”深挖源代码,最后它都会指向Any类。请注意,类型不是正规的类,虽然他们看起来是。我们会在后面的文章中详细讨论。

Hindley-Milner算法不支持子类型,但本质上子类型存在于多范式世界里。这也是为什么Scala不使用HM算法的另一个原因。

让我们来通过下面的示例来理解子类型。

我们构建了一个异质列表。如果可能,子类型把低类型转换成高类型。第一个示例是把一个Int类型转换成Double类型的简单例子。如果不能适配,它会去到顶级,例如Any类型。全部这些转换都可以翻译成上面类型系统体系。

这使得面向对象编程处理起来非常简单。

更多信息,请访问Scala官方文档

何时使用类型推断

这里有一条细线通过类型推断把动态类型(无类型)和静态类型进行了划分。正如他们所说的那样“所有的代码都应该看起来像是优美的散文”,知道何时使用他们以及何时不使用很重要。

(1)何时使用?

它何时节省了编程时间和类型信息在哪并不重要。场景可以是在一个函数的内部,或者在一个循环里,此处关于类型的信息显而易见。

(2)何时不用?

简单地,例如它不应该让阅读代码的程序来猜测类型,这时类型信息是重要的。

它很难给出一个代码示例,因为它真的依赖于深思熟虑的应用。处理这种情况唯一极其简单的方式是和资深程序员一起评估代码走查,看下他们是否能理解他们。

随后,全部编写的代码为O(K),而阅读代码的为O(N),其中K会是一个常量,没有太多变动,因为只有一个人会写代码,而N会是你的团队中尝试阅读代码的人数。把K和团队大小相乘。

猜测来自错误,错误来自坏的代码,坏的代码来自挫败,失败导来自杀人的斧头

这是关于代码可读性,而不是其他。自由来自责任。

恭喜你!!如果目前你已经理解/到达了这里,那么你应该为自己感到骄傲。与其说这是一个相当难的主题,我会说它是一个围绕着你的大脑、不是很直观的主题。

敬请继续关注!!这只是个开始。

参考


------------------------ 

© 著作权归作者所有

共有 人打赏支持
暗夜在火星

暗夜在火星

粉丝 150
博文 160
码字总数 310930
作品 1
广州
程序员
Scala学习笔记(2)-基础语法

秉着简洁而不失完整的的原则,这章只把Scala主要语法和与Java不同的内容列出来,以后章节也如此,内容以简洁为主,太长了自己都被吓着了,也没耐心看下去。 1.Scala解释器使用,这里不做介绍...

山海经
2013/08/25
0
0
Scala编程指南——用更少的字做更多的事

本文为《Programming Scala》的中文译文《Scala 编程指南》的第二章,在《Scala语言编程入门指南》我们介绍了Scala语言编程的入门,在上一章中我们以几个撩拨性质的Scala 代码范例作为章节结...

mj4738
2011/11/01
0
0
Scala笔记整理(一):scala基本知识

[TOC] Scala简介 Scala是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala运行在Java虚拟机上,并兼容现有的Java程序。 Scala源代码被...

xpleaf
04/18
0
0
深入理解Scala - 复合语言

本文内容主要来自《Scala in Depth》的第一章。主要介绍Scala是一门集面向对象编程和函数编程的复合语言。 多范型语言 Scala除了是面向对象和函数式的语言外,它还是: 泛型语言 脚本语言 命...

开源中国驻成都办事处
2014/04/03
0
2
Scala学习笔记-基础语法

Scala学习笔记-基础语法 OneCoder2016-09-2046 阅读 Scala 上手学习Scala语言。先熟悉一下语法。对于Scala笔者也是完全的新手,对scala的设计思想和实现原理没有太多了解。错误在所难免,还望...

OneCoder
2016/09/20
0
0
Scala基础语法

Scala 是一种有趣的语言。它一方面吸收继承了多种语言中的优秀特性,一方面又没有抛弃 Java 这个强大的平台,它运行在 Java 虚拟机 (Java Virtual Machine) 之上,轻松实现和丰富的 Java 类库...

岁月留痕
2015/12/08
35
0
scala语言与java的区别

scala支持关联映射,如可以用(key -> value)表示一个键值对 scala中的所有类型都是对象,包括基本数据类型 scala中的case语句用来判断接收的消息,比java中的switch...case...更专注 receiv...

jhonephone
2014/09/03
0
0
函数和闭包之函数字面量的短格式

Scala提供了许多方法去除冗余信息并把函数字面量写得更简短。注意留意这些东西,因为它们能让你去掉代码里乱七八糟的东西。一种让函数字面量更简短的方式是去除参数类型。因此,前一节带过滤...

柳哥
2014/06/07
0
0
Scala的foreach和for枚举功能一瞥

一句印象深刻的话,Alan Kay(Smalltalk发明者)说得一句话: “I’m not against types, but I don't know of any type systems that aren't a complete pain, so I still like dynamic ty......

hanzhankang
2014/02/15
0
0
Scala 2.8 发布第一个候选版

今天是ScalaDay 2010的第一天,同时期盼已久的Scala2.8的第一个候选版也已经发布。Scala 2.8 包含了大量bug修正以及增加了许多新的特性。 新特性: 集合类库重新设计 新的数组实现,允许多态...

红薯
2010/04/16
623
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

shell中的函数、shell中的数组、告警系统需求分析

shell中的函数 格式: 格式: function f_name() { command } 函数必须要放在最前面 示例1(用来打印参数) 示例2(用于定义加法) 示例3(用于显示IP) shell中的数组 shell中的数组1 定义数...

Zhouliang6
41分钟前
1
0
用 Scikit-Learn 和 Pandas 学习线性回归

      对于想深入了解线性回归的童鞋,这里给出一个完整的例子,详细学完这个例子,对用scikit-learn来运行线性回归,评估模型不会有什么问题了。 1. 获取数据,定义问题     没有...

wangxuwei
今天
0
0
MAC安装MAVEN

一:下载maven压缩包(Zip或tar可选),解压压缩包 二:打开终端输入:vim ~/.bash_profile(如果找不到该文件新建一个:touch ./bash_profile) 三:输入i 四:输入maven环境变量配置 MAVEN_HO...

WALK_MAN
今天
0
0
33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作

10.19 iptables规则备份和恢复 10.20 firewalld的9个zone 10.21 firewalld关于zone的操作 10.22 firewalld关于service的操作 10.19 iptables规则备份和恢复: ~1. 保存和备份iptables规则 ~2...

王鑫linux
今天
1
0
大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
今天
0
0
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
今天
2
0
HFS

FS,它是一种上传文件的软件。 专为个人用户所设计的 HTTP 档案系统 - Http File Server,如果您觉得架设 FTP Server 太麻烦,那么这个软件可以提供您更方便的档案传输系统,下载后无须安装,...

garkey
今天
1
0
Java IO类库之BufferedInputStream

一、BufferedInputStream介绍 /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * sup......

老韭菜
今天
0
0
STM 32 窗口看门狗

http://bbs.elecfans.com/jishu_805708_1_1.html https://blog.csdn.net/a1985831055/article/details/77404131...

whoisliang
昨天
0
0
Dubbo解析(六)-服务调用

当dubbo消费方和提供方都发布和引用完成后,第四步就是消费方调用提供方。 还是以dubbo的DemoService举例 -- 提供方<dubbo:application name="demo-provider"/><dubbo:registry address="z...

青离
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部