Scala 自身类型(self-type) 解析

Scala 有一个自身类型(self-type) 的东西,由来已久,居然今天才发现。如果一个类或 trait 指明了 self-type 类型(包括类和特质),它的子类型或是对象也必须是相应的类型。它产生的效果与继承(或 mixin) 颇有几分相似。self-type 的语法是 this 的别名: 某一类型(class 或 trait), 直接看一个例子:

上面 this: User => 中的 this 只是一个别名,可以是 self 或任何有效标识(如  abc: User),这里使用 this 等于未指定别名,与原本的 this 重叠了。如果声明为非 this 的话则可以这么用 阅读全文 >>

Akka Actor: 从最简单的例子开始

Akka 是什么?它提供了 JVM 上的 Actor 编程模型 -- 同时兼顾了并发与分布式。它由 Scala 编写的,替代了 Scala 本身的 Actor。Actor 视线程为重量级的资源,能够以少量的内存胜任更高的并发,类似的东西有纤程,协程。有一个数据对比是同样的 1GB 内存,可以创建 2.7M 个 Actor, 而线程只能创建 4096 个,仅供参考,当然 Java 也是会基于线程池来执行的。

Actor 增加了程序的灵活性,并减轻了复杂度(标准的赞美之辞)。

所谓 Action 编程模型兼顾并发与分布,是由于让你编程时可以不用考虑线程,线程配置成为部署的范畴; Actor 之间通信只能发送异步消息,Actor 可以分布在同一 JVM, 不同 JVM, 或是不同物理机器上。

因为 《Akka IN ACTION》中提供了第一个例子起点着实有点高,所以网上找来了一个了解 Akka Actor 的最简单例子,来自于 Simple Scala Akka Actor examples (Hello, world examples)。并非纯属翻译,主要是为了练手,所以不完全一致: 阅读全文 >>

Scala 中应用 Future 并发编程

Java 世界里进行并发编程有 Future 和  ExecutorService(当成 ThreadPool 来对待),及至 Java 8 引入了更为趁手的 CompletableFuture。那么使用 Scala 该如何进行并发编程呢?Scala 能毫无障碍的使用 Java 类库,所以完全可以用 Java 的 API 来使用线程池,只是那不太 Scala 罢了。

既然是 Scala, 就尽量写成 Scala Style 吧,Scala 也有自己的 Future, 还有 Promise 呢? 至于 Promise 与 Future 多大区别,语义上似乎也差不多,只看到 Promise 中有一个 Future 的属性。如果想玩得高级一点的话就该把  Actor 弄起来,它算是所谓的纤程,多个  Actor 可跑在同一个线程中,当然启动要快,内存消耗少,还避免了上下文切换。

这里还是先体验 Scala Future 的用法。Future 本身只是描述了一个任务,及将要获得的结果(或执行的动作),因此那样一个任务也是要放到线程池中去执行。这和 Java 的 Future/ThreadPool 是一样的概念。稍有不同的是线程池的创建与使用,线程池的默认大小配置等。看个简单的应用示例,本次测试的 Scala 版本是 2.11.12,为了突出实际的线程池大小,我们把任务数设置为 20 个

Scala Future 并发编程体验

阅读全文 >>

体验 Scala 2.12 支持的 Java 8 风格(SAM) Lambda

上一次关注 Scala 新版本特性还是在将近五年前,针对的是  Scala 2.10. 后来也一直在使用 Scala,基本上是 Scala 2.11,但对 Scala 2.11 所带来的新特性基本无知,大约有个 Macro 功能,没什么机会用上,应用 sbt 时稍有接触。还是老句老话,了解新特性最可靠的文档是每个版本的的 Release Notes, 比如 Scala 2.12.0 Release Notes.

其中 Scala 2.12 带来的主要特性在于对 Java 8 的充分支持:

  1. Scala 可以有方法实现的 trait 直接编译为带默认方法的 Java 接口
  2. Lambda 表达式无需生成相应的类,而是用到 invokedynamic 字节码指令(这个是 Java 7 加进来的新指令)
  3. 最方便的功能莫过于终于支持 Java  8 风格的 Lambda,即功能性接口的 SAM(Single Abstract Method)

Scala 的 Lambda 内部实现

这儿主要是体验 Scala 2.12 如何使用 Java 8 风格的 Lambda. 在 Scala 2.12 之前,Scala 对 Lambda 的支持是为你准备了一大堆的 trait 类,有

  1. Function0, Function1, ...... Function22 (接收多个参数,返回一个值)
  2. Product1, Product2, ...... Product22 (函数返回多个值,即 TupleX 时用的)

阅读全文 >>

IntelliJ IDEA 中创建 Maven Scala 项目

Scala 项目看家的构建工具当然是 SBT, 假如我们已习惯于 Maven, 想要用 Maven 来构建 Scala 项目该如何做呢?那首先要找到一个 Maven Scala 相应的 Archetype, 然后用命令 mvn archetype:generate 或是在 IntelliJ IDEA 使用 Maven 项目创建向导来选择一个 Maven Scala Archetype。这里主要介绍 IntelliJ IDEA 中 Maven 向导创建 Scala 项目的方式。

首先确保我们已安装了 IntelliJ IDEA 的 Maven 和  Scala 插件。插件中自带了 org.scala-tools.archetypes:scala-archetype-simple:1.2 的 Maven archetype, 这是一个貌视 Scala 官方的 archetype。我们可以尝试基于它来创建一个 Maven Scala 项目。通过 IntelliJ IDEA 的菜单 File/New/Project..., 在弹出的窗口中选择 Maven/Create from archetype, 然后找到 scala-archetype-simple, 自带版本为 1.2, 当前最新版也不过 1.3, 那还是  2010 年建立,别提有多老了。 阅读全文 >>

函数定义 Kotlin V.S. Scala

关注 Kotlin 已有段时日了,真是因为 Google 把它扶正而跑来跟风。因为进行想在 Java 与 Scala 间找一个折中的编程语言,也就是 Kotlin。这是一篇好几月前列的我 想像中理想编程语言的几个特征,琢磨来去当今也就 Kotlin 比较符合我的口味。很早就想买 《Kotlin IN ACTION》这本书,因那是 Kotlin 1.1 刚出,而出版的书只涵盖到了 Kotlin, 所以未出手。看看再有一本好的那样的书估计也不是一时半会儿,所以今天还是把那本书弄到手了,至于 Kotlin 1.1 后的特性自个去补充。

尽管书中未提及 Kotlin 语言的设计灵感来自于何种语言,  但我的直觉就是与 Scala 太多相似之处,但没有 Scala 简单,并揉合一些 Swift 的特性,因此我在阅读 《Kotlin IN ACTION》时更多的会和 Scala 相比较。

第一个主题是关于 Kotlin 函数的定义与约定。Kotlin 的基本定义格式与 Scala 是类似的

//Kotlin
fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

注:Kotlin 也像 Scala 一样,if 不再是一个控制语句,而是一个表达式,所以它是有返回值的。与  Java 有不同的是,Kotlin 的赋值语句是没有返回值的,不能用作 val b = (a = 3), 而 Scala 的赋值语句总是返回 Unit 阅读全文 >>

Scala 的参数检查与断言: require, assert, assume 和 ensuring

似乎 C/C++ 的编程人员相比于 Java 更偏爱于断言,JDK 1.4 才开始引入 assert 的支持,但默认是关闭的,需要用 -ea 编译选项打开,否则代码中的 assert 语句全被忽略,一般会在单元测试中开启该选项。简单回顾一下 JDK 自带的断言,它用两种写法

assert object != null;
assert object != null : "object can't be null";

第一个参数是个 bool 值,断言失败只会笼统的抛出java.lang.AssertionError 异常,并不区分是在检验方法参数还是中间运算结果。严谨来说我们会希望参数检查不通过时抛出 java.lang.IllegalArgumentException; 而中间运算结果的断言不过希望抛出 java.lang.AssertionError, 最好是 java.lang.IllegalStateException

很多时候我们不会去使用 -ea 编译选项,也就是主动放弃了 JDK 本身的断言功能。介于两个因素(不同的断言错误和默认的断言选项关闭),Scala 为我们提供了更方便的参数检查与断言方法,它们来自于 Predef, 其所定义的方法可以直接使用

阅读全文 >>

Giter8 -- 把项目布局模板放到 GitHub 上

因为学习或做些小 Demo, 会临时建立一个项目, 项目的布局也常有类似, 不想每次为一个 Maven 项目而执行 mkdir -p example/src/{main,test}/{java,resources}, 或是通过 IDE 来创建, 于是萌生了把自己常用的项目模板放到 GitHub 上的想法. 我们当然可以把直接在 GitHub 上创建一个个项目模板仓库, 想用时只要 git clone 下来, 但克隆的总是与 GitHub 上相应的仓库有关联.

Google 了, 有不少方法能建立项目基本框架, 如

  1. 创建 Maven 项目骨架,  mvn archetype:generate -DarchetypeGroupId=.....
  2. sbt 的 np 插件可以快速生成项目目录
  3. YEOMAN 也有自己的 Generator, 很强大也复杂

再就是现在要介绍的, 比较适合于我的口味的 Giter8, 简单实用, 定义模板更是轻松自如. Giter8 是构建在 sbt launcher 之上的用于从 GitHub 或其他任何 Git 仓库中攫取项目模板的命令行工具. 模板定义简单, 支持变量的提示输入. 下面是安装, 使用, 以及建立自己的模板: 阅读全文 >>

Scala 中置, 前置, 后置操作符

拟此篇以温习 Scala 对方法调用上的一些约定. 标题中说是关于操作符的事, 其实 Scala 像有了访问方法和属性的一致性原则一样, 可以说操作符与方法更是统一的, 或者说只有方法调用. 此处所称的操作符只不过是 Scala 对无参(prrameterless), 或只有一个参数的方法, 和特殊的四个 unary_+, unary_-, unary_!, unary_~ 方法的便捷的调用约定格式.

一. 中置操作符(对只有一个参数方法的调用约定, a plus b)

case class MyNumber(value: Int) {
  def +(that: MyNumber) = MyNumber(this.value + that.value)
}

调用方式

第一行是用点语法的标准方法调用格式, Scala 在当方法只有一个参数时, 可以省略点, 以及括号, 因此可写为上面第二行种的格式. 所以方法 + 就化身为了中置操作符了. 阅读全文 >>

sbt 最简单的带输入任务 inputTask

在 sbt 中我们可以定义 settingKey, taskKey 和 inputKey. inputKey 接收输入的任务更具灵活性,虽然在 sbt 中 taskKey 和  inputKey 数量比例为 25:1,但仍然不可忽视了 inputKey 的贡献。

起初在阅读 sbt 关于 inputKey 的资料时,一不小心就被带入到 Parser 上去了。其实还不如开门见山,先跳过 Parser 部份,示范 inputKey 任务中直接处理用户的原生输入。

这里有两个最简单的 sbt inputKey 的示例

一. 命令后非空格起全部输入当作一个字符串

trimmed() 方法能去除了两边的空格,如果是 token(any.* map(_.mkString)).parse 则两边空格都会算上,在 demo1 abc  的 abc 两边的空格也都会算在输入参数里

> demo1 abc "abc"
abc "abc"


sbt  的  input task  参数居然默认是紧接着命令开始的,如上面如果输入是 demo1xxx, demo1 任务接收到的参数是 xxx. 如果同时也定义了另一个任务是 demo1x, 那么输入 demo1xx 就会执行 demo1x 任务,参数是 xx. 从后往前进行匹配任务名。这个还有点奇怪,因为我以前任何时候都是自然的把命令与参数用空格分开,它却可以把命令与参数写在一起。

 


二. 像调用 main 方法一样传入参数

阅读全文 >>