我们每个人都从亲生父母那里继承了一套被称为 DNA 的化学指令,它们影响着我们身体是如何构成的。 所有已知的生命都依赖 DNA!
注意:完成这道练习并不需要了解任何关于核苷酸或 DNA 的知识。
DNA 是一条由其他化学物质组成的长链,其中最重要的是四种核苷酸:腺嘌呤、胞嘧啶、鸟嘌呤和胸腺嘧啶。 一条 DNA 链可以包含数十亿个这四种核苷酸,而它们出现的顺序非常重要! 我们把一小段 DNA 中这些核苷酸的顺序称为“DNA 序列”。
我们用这些核苷酸的有序集合来表示 DNA 序列,常见的做法是用一串字符,比如用 "ATTACG" 表示一段包含 6 个核苷酸的 DNA 序列。 'A' 代表腺嘌呤,'C' 代表胞嘧啶,'G' 代表鸟嘌呤,'T' 代表胸腺嘧啶。
给定一个表示 DNA 序列的字符串,统计其中每种核苷酸各有多少个。 如果字符串中包含不是 A、C、G 或 T 的字符,那么它就是无效的,你应该报错。
例如:
"GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2
"INVALID" -> error
Either的一个常见用途是表示一个可能出错的计算
(如果实际错误无关紧要,那么更简单的Option类型可能是更好的选择)。
没有错误时,结果通常是一个Right(助记:即“正确”的那个值),
而错误则是一个Left,例如一个包含错误信息的Left[String]。
注意,在 Scala 2.12 中,Either默认是右偏的,因此对于filter、map、flatMap这类操作,或者在 for 推导式中,它的行为都符合预期。
如果你不熟悉Either,可以阅读这篇教程。但要注意,这篇教程讲的是 2.12 之前的 Scala 版本。如果你用的是 Scala 2.12,可以放心忽略RightProjection,并省略.right。
Either是一种所谓的 Monad,它涵盖了一个“计算层面”,在这里就是错误处理。
正确使用 Monad 可以写出非常简洁、优雅且易读的代码。用得不恰当则很容易适得其反。
想了解更多,可以看看这个视频。
对于Either,有几条经验法则:
def add1(x: Int): Either[String, Int] = Right(x + 1)
不如写成
def add1(x: Int): Int = x + 1
(有Either.map可以应用这类简单的函数,
所以不必用Either把它们弄得乱糟糟的)。
2. 不是真的需要,就不要“拆包”。
通常已经有现成的内置函数能满足你的目的。过早拆包的标志是isLeft/isRight或模式匹配。例如,与其写成
val x: Either[String, Int] = ...
if (x.isRight) x.right.get + 1 else x.left.get
// or
x match {
case Right(n) => n + 1
case Left(s) => s
}
不如写成
x fold (identity, _ + 1)
Either实例时,推荐这样做。与其写成val xo: Either[String, Int] = ...
val yo: Either[String, Int] = ...
val zo: Either[String, Int] = ...
xo.flatMap(x =>
yo.flatMap(y =>
zo.map(z =>
x + y + z)))
不如写成
for {
x <- xo
y <- yo
z <- zo
} yield x + y + z