函数定义 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 阅读全文 >>

类别: Kotlin, Scala. 标签: . 阅读(57). 评论(0) »

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, 其所定义的方法可以直接使用

阅读全文 >>

类别: Scala. 标签: , . 阅读(259). 评论(0) »

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. 标签: , . 阅读(83). 评论(0) »

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)
}

调用方式

MyNumber(10).+(MyNumber(20))   //标准调用格式
MyNumber(10) + MyNumber(20)    //只有一个参数时, 不用点, 不用括号

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

类别: Scala. 标签: . 阅读(81). 评论(0) »

sbt 最简单的带输入任务 inputTask

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

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

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

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

import complete.DefaultParsers._

val demo1 = inputKey[Unit]("Demo1 inputTask")
demo1 := {
 val input = trimmed(any.* map(_.mkString)).parsed
 println(input)
}

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 方法一样传入参数

阅读全文 >>

类别: Scala. 标签: , . 阅读(63). 评论(0) »

Scala 和 Java 的集合类型相互转换

在 Scala 和 Java 混合编程时免不了需要进行集合类型在两种语言间相互转换,更多的是在 Scala 调用 Java 的方法时把 Scala 的集合转型为 Java 的集合。典型场景是:

public void process(java.util.List<String> orderIds) {
  ......
}

上面定义的 Java 方法,如果要在 Scala 中调用它,不考虑两种语言的集体类型转换的话,可以直接传入 Java 代码要求的类型,像这样

val orderIds = new java.util.ArrayList[String]
orderIds.add("SJ001")
process(orderIds)

这样当然可以,但不能享受到 Scala 语言中集合使用的便利性,如快捷的构造,丰富的怪异的方法(++, ::, ## 等)。所以希望此时 Scala 中调用 process()  能接近这种方法

process(List("SJ001", "SJ002"))

特别是当 Java 接受一个 java.util.Map 时,能在 Scala 里直接传入 Map("key1" -> "value1",  "key2" -> "value2") 就方便许多。

用方法来完成 Scala 和 Java 间对应集合类型的转换当然没问题,但别忘了 Scala 还支持隐式转换,那就是只要在 Scala 代码中引入 collection.JavaConversions._ 对于上面的方法在 Scala 中就可以直接传入 Scala 的 List() 了。也就是 阅读全文 >>

类别: Scala. 标签: , . 阅读(539). 评论(0) »

让 Scala 测试方法名中的空格不再显示为 $u0020

在 Scala 中借助于斜撇号我们可以使用关键字或任何字符为作为变量或方法名,例如下面的方法都是合法的:

scala> def `if`: Unit = {}
if: Unit

scala> def `我是谁?`: Unit = {}
我是谁$qmark: Unit

scala> def `just do it`: Unit = {}
just$u0020do$u0020it: Unit

对了,Scala 2.11.6 在显示有些字符时会进行编码,像上面的 ? 和 空格。而用 2.11.7 的 Scala  控制台下居然原样显示,不编码(这是在进一步试难时发现的)。

我们在用 Scala 写 JUnit 风格的单元测试, 由于 JUnit 不支持像 TestNG 那样在方法名上加描述,所以方法名必须完成自我描述。依照严格的方法命名的话,势必要用驼峰方式或下划线把单词分开,如

def getOneHunderIfSixtyPlusFouty: Unit = { ... }
def get_one_hunder_if_sixty_plus_forty: Unit = { ... }

注:如果用 Scala 写 Spec 测试代码另当别论,因为有些情况下必须用 JUnit 风格(就用 JMockit 时) 阅读全文 >>

类别: Scala. 标签: , . 阅读(40). 评论(2) »

sbt 任务间的依赖

项目中的 build.sbt 中发现定义任务时有 task2 <<= task1 map {...} 这样任务依赖的写法, 这个  <<= 方法有点晦涩难懂, 读过 sbt in action 之后才知道这是 sbt 0.12 或之前的做法, sbt 0.13 之后不这么用了, 直接访问下 task1.value 就行, 因此前面可改写为 task2 := {task1.value; ...}, 这也使得定义任务依赖时与普通任务一致风格了. 新的写法得益于 Scala 2.10 的宏特性, 后面还会讲到.

对于依赖于多个任务的情况, 在 sbt 0.13 前面分别是这样的, 假定有三个 Task(task1, task2, 和 task3)

val task1 = taskKey[Int]("task 1")
val task2 = taskKey[Int]("task 2")
val task3 = taskKey[Int]("task 3")

如果 task3 依赖于 task1 和 task 2

sbt 0.13 前后版本中的写法分别是

//sbt 0.12 及更早版本, 当然 sbt 0.13 中也能这样写
//http://www.scala-sbt.org/0.12.2/docs/Detailed-Topics/Tasks.html#dependencies
task3 <<= (task1, task2).map((t1, t2) => t1 + t2)  //task1, task2 并发执行

//sbt 0.13 后, 推荐这种新写法
task3 := task1.value + task2.value //task1, task2 也是并发执行

像任务的 .value 属性其实是一个宏定义, 源码 阅读全文 >>

类别: Scala. 标签: . 阅读(24). 评论(0) »

ScalaTest + Selenium 集成测试

在 Play 1 和 Play 2 中都内置了 Selenium 集成测试工具, 这里自己尝试自己单独测试用 ScalaTest + Selenium 来做简单的集成测试. Selenium 可以支持内置的无界面 Java 实现的浏览器, 也可以用外部浏览器, 如 Safari, Firefox, Chrome, IE, Opera 或移动设备的浏览器. 使用不同外部浏览的方式或用插件(Safari/Firefox 等) 或是像借助于 Chromium 来驾驭 Chrome 浏览器.

而我们这里要用的 ScalaTest 2.2.6 在包 org.scalatest.selenium 有以下几个特质 Chrome, Driver, Firefox, HtmlUnit, InternetExplorer, Page, Safari 和  WebBrowser. 由此可以看出 ScalaTest 默认支持的浏览器. 若单论 Selenium 本身, 它可强大的暂时超乎我的想像, 可以自建服务器, 选择浏览器分发测试任务. 我们知道使用 Selenium 的好处是不光可以像通常那样断言页面静态文本, 还能执行 Javascript 脚本, 所以可断言动态内容.

本人开发环境为 Mac OS, 可以成功让 Selenium 测试跑在内置 Java 浏览器, 和外置的  Safari, Chrome 浏览器中, Firefox 的插件未安装成功.

让事实说话, 仍然让一个最简单的例子自己说话, 创建的是一个 sbt 项目, 尽量把目录最简化, 只有 build.sbt 文件和 test/IntegrationTest.scala 测试代码, 内容分别为 阅读全文 >>

类别: Scala. 标签: , , . 阅读(81). 评论(0) »

建立 Play 2 框架一样的目录布局

sbt 项目继承并扩展了 Maven 的默认项目布局, 加入了 Scala 代码的支持, 所以目录如 Shell 命令 mkdir -p src/{main,test}/{java,scala,resources} 生成的目录结构, 即

.
└── src
    ├── main
    │   ├── java
    │   ├── resources
    │   └── scala
    └── test
        ├── java
        ├── resources
        └── scala

这个目录目录虽然很清晰, 但把 Java 和 Scala 代码拆在两处没多大必要, 其次是层次多了点. 因使用 Play Framework 时日有点久了, 比较习惯于 Play 2 改造后的项目布局. 我们启动到 Play 2 的 activator(其实就是加入了定制的 sbt) 控制台, 用命令看它的目录布局 阅读全文 >>

类别: PlayFramework, Scala. 标签: . 阅读(118). 评论(0) »
Page 1 of 612345...Last »