sbt笔记六 More Kinds of Setting(待续)

sbt设置详解

http://www.scala-sbt.org/release/docs/Getting-Started/More-About-Settings.html

Refresher: Settings

记住,构建定义创建一个Setting列表,然后这个列表用于转换sbt的构建描述(它是键值对的映射)。一个Setting是一个将sbt早先的映射作为输入、一个新的映射作为输出的转换。这个新映射作为sbt的新状态。

不同的setting通过不同的方式转换这个映射。早些时候,你已经读到:=方法了。

:=创建的Setting在新的,改变了的映射中设置了固定的,常量的值。例如,如果你用setting name := "hello"来转换一个映射,新的映射有一个字符串"hello"存储在name键。

Settings must end up in the master list of settings to do any good(看不懂)(在build.sbt中的行都自动结束在list中,但是在.scala文件中你可以错误地创建一个Setting却没有放到sbt能够发现的地方(but in a .scala file you can get it wrong by creating a Setting without putting it where sbt will find it))

追加到原先的值:+=和++=

用:=替换是最简单的转换,但是key也有其他的方法,如果SettingKey[T]中的T是一个序列,也就是说,key的值类型是一个序列,你可以向序列追加值,而不是替换它。

  • +=可以向序列追加单个元素。
  • ++=可以与另一个序列连接。

例如,Compile作用域中的sourceDirectories键有一个Seq[File]的值。默认情况下,它的值包含src/main/scala。如果你也想编译source文件夹下的源码,可以添加这个文件夹:

sourceDirectories in Compile += new File("source")
或者,用sbt包中更便利的file()函数:
sourceDirectories in Compile += file("source")
(file()仅创建一个新的File。)

可以用++=同时添加多个文件夹:
sourceDirectories in Compile ++= Seq(file("sources1"), file("sources2"))

Seq(a, b, c, ...)是Scala中创建序列的标准语法。

完整替换默认源码文件夹,无疑要用:=:

sourceDirectories in Compile := Seq(file("sources1"), file("sources2"))

转换一个值(Transforming a value):~=

如果想向前追加Compile中的sourceDirectories,或过滤掉默认文件夹中的一个,要怎么做呢?

你可以创建一个依赖于先前值的Setting。

  • ~=将一个函数应用到setting先前的值,并创建一个相同类型的新值。

修改Compile中的sourceDirectories,可以如下方式使用~=:

// filter out src/main/scala
sourceDirectories in Compile ~= { srcDirs => srcDirs filter(!_.getAbsolutePath.endsWith("src/main/scala")) }

在这里,srcDirs是匿名函数的入参,并且Compile中的sourceDirectories会被传入匿名函数。这个函数的结果将作为Compile中sourceDirectories的新值。

一个简单的例子:

// make the project name upper case
name ~= { _.toUpperCase }

如果key是SettingKey[T]或TaskKey[T]类型,则传入的函数必须是T => T类型的。这个函数将key的值转换为类型相同的另一个值。

基于另一个key的值,计算一个值:<<=

~=根据key先前的值来定义一个新值。但如果你想根据另一个key的值来定义一个新值呢?

  • <<=允许你用另外一个任意的key的值,来计算一个新的值。

<<=有一个Initialize[T]类型的参数。一个Initialize[T]的实例是一个计算,他将一个key集合所关联的值作为输入,并返回一个T类型的值(基于其他的值)。它初始化了一个T类型的值。

给定一个Initialize[T],<<=返回一个Setting[T](就像:=,+=,~=等)。

微不足道的Initialize[T]:用<<=依赖于另一个key

所有的key都扩展自Initialize特质。所以key就是最简单的Initialize:

// useless but valid
name <<= name

当作为一个Initialize[T],一个SettingKey[T]计算它当前的值。所以name <<= name将name的值,设为name已有的值。

如果你要将一个key设为另一个key,这就比较有用。两个key必须拥有相同的值类型。

// name our organization after our project (both are SettingKey[String])
organization <<= name
如果值类型不一致,你需要从Initialize[T]转换成另一个类型,就像Initialize[S]。这在Initialize的apply方法中完成,像这样:
// name is a Key[String], baseDirectory is a Key[File]
// name the project after the directory it's inside
name <<= baseDirectory.apply(_.getName)
在Scala中apply很特别,这意味着你可以用函数语法调用这个对象;所以可以这么写:
name <<= baseDirectory(_.getName)

它用_.getName函数转换baseDirectory的值,函数_.getName得到一个File并返回String。getName是标准java.io.File对象的方法。

Setting依赖

在setting name <<= baseDirectory(_.getName)中,name有一个baseDirectory的依赖。如果把上文放在build.sbt中,并且运行sbt交互控制台,然后输入inspect name,你就会看到(局部):

[info] Dependencies:
[info]  *:base-directory

这就是sbt如何知道一个setting依赖于另一个setting。牢记一些setting是描述任务的,所以这种方式也创建任务间的依赖。

例如,如果你运行inspect compile,你将看到它依赖于另一个key compile-inputs,并且如果你运行inspect compile-inputs,它依次依赖于其他的key。跟随依赖链然后奇迹发生了。例如当你输入compile,sbt会自动执行update。它能够工作是因为,compile计算所需的值,需要sbt先执行update计算。

通过这种方式,所有sbt中的构建依赖都是自动的,而不是明确地定义。如果你在另一个计算中使用一个key的值,那么这个计算就依赖于那个key。这很管用!

复杂的Initialize[T]:用<<=依赖多个key

为了支持多个key的依赖,sbt为Initialize对象元组添加apply和identity方法。在Scala中,元组写成(1, "a")(它的类型是(Int, String))。

2013-1-28 22:40



2012-1-28
不要问为什么这篇没有内容,我不会告诉你我把它扔家里了。
家里电脑没有啊,为什么找不到了呢,我明明记得这篇我看过的,难道是光看没写下来吗?好吧,再找时间写吧。
找到了,哈哈,不过就完成了一半,先粘上来吧,别不小心又找不到了。前面好几篇都忘了原文,这篇把原文链接加上,然后赶紧睡觉去,扛不住了。

转载于:https://my.oschina.net/u/580483/blog/105686

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值