从左到右自变量类型推断
我有一种情况,我希望根据(几个,比如5到10)optionals的存在对对象进行修改。所以基本上,如果我是势在必行做到这一点,是我的目标是为:从左到右自变量类型推断
var myObject = ...
if (option.isDefined) {
myObject = myObject.modify(option.get)
}
if (option2.isDefined) {
myObject = myObject.someOtherModification(option2.get)
}
(请注意:也许我的对象是可变的,也许不是,这不是点这里。)
我想那会更好看,如果我试图执行写这个的流畅的方式,如(伪代码...):
myObject.optionally(option, _.modify(_))
.optionally(option2, _.someOtherModification(_))
于是我开始了示例代码,其中的IntelliJ并不突出作为错误,但实际上并不构建。现在
class MyObject(content: String) {
/** Apply a transformation if the optional is present */
def optionally[A](optional: Option[A], operation: (A, MyObject) => MyObject): MyObject =
optional.map(operation(_, this)).getOrElse(this)
/** Some possible transformation */
def resized(length : Int): MyObject = new MyObject(content.substring(0, length))
}
object Test {
val my = new MyObject("test")
val option = Option(2)
my.optionally(option, (size, value) => value.resized(size))
}
,在我的情况下,MyObject
类型是一些外部API的,所以我创建了一个隐式转换帮助,所以它确实是这样的:
// Out of my control
class MyObject(content: String) {
def resized(length : Int): MyObject = new MyObject(content.substring(0, length))
}
// What I did : create a rich type over MyObject
class MyRichObject(myObject: MyObject) {
def optionally[A](optional: Option[A], operation: (A, MyObject) => MyObject): MyObject = optional.map(operation(_, myObject)).getOrElse(myObject)
}
// And an implicit conversion
object MyRichObject {
implicit def apply(myObject: MyObject): MyRichObject = new MyRichObject(myObject)
}
而且那么,我这样使用它:
object Test {
val my = new MyObject("test")
val option = Option(2)
import MyRichObject._
my.optionally(option, (size, value) => value.resized(size))
}
而这一次,它在IntelliJ和编译时失败,因为0的类型不明: Error:(8, 26) missing parameter type my.optionally(option, (size, value) => value.resized(size))
为了使它的工作,我可以:
- 积极指定类型的
size
说法:my.optionally(option, (size: Int, value) => value.resized(size))
- 重写
optionally
到令行禁止版本
他们都不是很差,但如果我可能会问:
- 是否有一个咖喱版本工作的原因,但一个多参数版本似乎无法推断参数化类型,
- 难道是写在没有指定实际类型
- ,并作为工作的方式奖金(虽然这可能是基于意见),你会怎么写它(某种
foldLeft
在我的脑海中出现一系列可选项......)?
一个选项:
// Out of my control
class MyObject(content: String) {
def resized(length : Int): MyObject = new MyObject(content.substring(0, length))
}
object MyObjectImplicits {
implicit class OptionalUpdate[A](val optional: Option[A]) extends AnyVal {
def update(operation: (A, MyObject) => MyObject): MyObject => MyObject =
(obj: MyObject) => optional.map(a => operation(a, obj)).getOrElse(obj)
}
}
object Test {
val my = new MyObject("test")
val option = Option(2)
import MyObjectImplicits._
Seq(
option.update((size, value) => value.resized(size)),
// more options...
).foldLeft(my)(_)
}
还不如只用你的optionally
的咖喱版本,就像你说的。
想想需要添加A型更好的方式有写这样说:
object Test {
val my = new MyObject("test")
val option = Some(2)
my.optionally[Int](option, (size, value) => value.resized(size))
}
另一种方式,如果你只是将管理一个类型,因为对象的创建,是将一般的类创作,但要小心,使用此选项,你只能有每个实例一个类型:
class MyObject[A](content: String) {
def optionally(optional: Option[A], operation: (A, MyObject[A]) => MyObject[A]): MyObject[A] =
optional.map(operation(_, this)).getOrElse(this)
def resized(length : Int): MyObject[A] = new MyObject[A](content.substring(0, length))
}
object Test {
val my = new MyObject[Int]("test")
val option = Some(2)
my.optionally(option, (size, value) => value.resized(size))
}
正如你所看到的,现在都在仿制药是地方是德EN由int类型,因为那是你最想要的是什么,这里是一个漂亮的答案告诉了原因:
(只是一部分,我想在这里也适用:)
4)当推断的返回类型比您想要的更普遍,例如Any。
感谢您的第一个建议。回想起来似乎很明显,而且更好。你的第二个命题也很好,但有限制,另外我实际上不能修改MyObject。你的答案的其余部分似乎并不适用,因为它不能解释为什么当暗示进场时推理停止工作...... – GPI
@GPI在这种情况下适用规则4):4)当推断的返回类型更一般时比你想要的,比如Any。 我的意思是你在哪里返回一般类型,当你想要一个特定的类型时,你不同意吗? –
@GPI无论如何,我删除了无关的部分来澄清答案,我一直都很乐意提供帮助。 –
我喜欢将可选类型的含义颠倒过来的想法,而不是MyObject(泛化:使参数化类型可转换,因此消除了另一端的任何参数化方法)。我同意你的结论:咖喱版至少看起来很好。让我觉得可能有些事情可以用证人类型来尝试(https://*.com/questions/8524878/implicit-conversion-vs-type-class?rq=1) – GPI
另请参阅http://pchiusano.blogspot。 hk/2011/05/making-most-of-scalas-extremely-limited.html关于你观察到的类型推断的限制 – PH88
感谢您的挖掘。我没有得到的是,在第一个示例实现(不含implicits)中,这实际上可行... – GPI