【发布时间】:2019-02-02 05:32:49
【问题描述】:
我一直遇到类型推断问题,我不确定我做错了什么,编译器中存在错误,或者是语言限制
我创建了一个虚拟示例来说明问题,用例没有任何意义,但相信我,我有一个有效的用例
假设我有这个代码
val function: (Int, String) => String = (_, _) => ""
implicit class Function2Ops[P1, P2, R](f: (P1, P2) => R) {
def printArgs(p1: P1, p2: P2): Unit = println(p1, p2)
}
function.printArgs(1, "foo")
有效并打印(1,foo)
现在,如果我将代码更改为(注意 by-name 参数)
val function: (Int, => String) => String = (_, _) => ""
implicit class Function2Ops[P1, P2, R](f: (P1, P2) => R) {
def printArgs(p1: P1, p2: P2): Unit = println(p1, p2)
}
function.printArgs(1, "foo")
它将打印(1,MyTest$$Lambda$131/192881625@61d47554)
现在,此时我可以尝试进行模式匹配和/或使用 TypeTag 来提取值,以防万一是按名称参数,但是, 我实际上想要实现的是做这样的事情
trait Formatter[T] {
def format: String
}
case class ReverseStringFormat(v: String) extends Formatter[String] {
override def format: String = v.reverse
}
case class PlusFortyOneFormat(v: Int) extends Formatter[Int] {
override def format: String = (v + 41).toString
}
implicit def noOpFormatter[T](v: T): Formatter[T] = new Formatter[T] {
override def format: String = v.toString
}
val function: (Int, => String) => String = (_, _) => ""
implicit class Function2Ops[P1, P2, R](f: (P1, P2) => R) {
def printArgs(p1: Formatter[P1], p2: Formatter[P2]): Unit = println( p1.format, p2.format)
}
function.printArgs(1, ReverseStringFormat("foo"))
请注意,主要目的是我应该能够传递参数的原始类型或格式化程序,这就是此扩展方法的签名使用Formatter[TypeOfOriginalParam] 的原因,这也是我使用implicit def noOpFormatter[T](v: T): Formatter[T] 的原因当我不想要任何格式时
现在,在这里,我无能为力,因为代码无法编译并出现此错误
Error:(22, 40) type mismatch;
found : ReverseStringFormat
required: Formatter[=> String]
function.printArgs(1, ReverseStringFormat("foo"))
如果我将隐式类的第二个类型参数设为按名称,我可以让它运行
val function: (Int, => String) => String = (_, _) => ""
implicit class Function2Ops[P1, P2, R](f: (P1, => P2) => R) {
def printArgs(p1: Formatter[P1], p2: Formatter[P2]): Unit = println( p1.format, p2.format)
}
function.printArgs(1, ReverseStringFormat("foo"))
这会打印(1,oof)
现在,主要问题是我想对任何函数执行此操作,无论它的任何参数是按值还是按名称。 这就是我卡住的地方,我可以为每种可能的情况组合创建不同的隐式类,无论是否存在名称参数,但这并不实用,因为我需要为从 Function1 到 Function10 的每个函数执行此操作,并且按名称和按值参数之间可能的组合数量会很大。
有什么想法吗?如果我只对类型感兴趣,我真的需要关心参数的惰性吗?我是在尝试做一些设计不支持的事情,还是编译器中的错误?
顺便说一句,这是我要避免的
val function: (Int, => String) => String = (_, _) => ""
val function2: (Int, String) => String = (_, _) => ""
val function3: (=> Int, String) => String = (_, _) => ""
val function4: (=> Int, => String) => String = (_, _) => ""
implicit class Function2Ops[P1, P2, R](f: (P1, => P2) => R) {
def printArgs(p1: Formatter[P1], p2: Formatter[P2]): Unit = println("f1", p1.format, p2.format)
}
implicit class Function2Opss[P1, P2, R](f: (P1, P2) => R) {
def printArgs(p1: Formatter[P1], p2: Formatter[P2]): Unit = println("f2", p1.format, p2.format)
}
implicit class Function2Opsss[P1, P2, R](f: (=> P1, P2) => R) {
def printArgs(p1: Formatter[P1], p2: Formatter[P2]): Unit = println("f3", p1.format, p2.format)
}
implicit class Function2Opssss[P1, P2, R](f: (=> P1, => P2) => R) {
def printArgs(p1: Formatter[P1], p2: Formatter[P2]): Unit = println("f4", p1.format, p2.format)
}
function.printArgs(1, "foo")
function2.printArgs(1, ReverseStringFormat("foo"))
function3.printArgs(1, "foo")
function4.printArgs(PlusFortyOneFormat(1), "foo")
它的工作原理(请注意,我随机使用了格式化程序或原始值,原始参数是按名称还是按值无关紧要)
(f1,1,foo)
(f2,1,oof)
(f3,1,foo)
(f4,42,foo)
但是不得不把所有这些都写给我似乎很奇怪
【问题讨论】:
-
非常好的问题。
-
val function: (Eval[Int], Eval[String]) => String和Eval怎么样? -
问题是我需要能够使用任何功能来做到这一点,我正在编写一个库,所以我无法控制用户将提供哪些功能,而且大多数时候他们将是方法转换为像
obj.method _这样的函数,所以我不能假设/强加任何关于参数的形状/类型的东西 -
也许将部分行为提取到类型类中?这样,您将有两种情况:按值和按名称,您可以为每个参数采用一个类型类实例,有效地处理所有 4 种组合。
-
@MateuszKubuszok 对不起,我不明白,类型类在这里如何帮助我? (也许是因为我在考虑真正问题的背景,但如果你能发布一个简单的例子,这将有助于我理解你的建议)
标签: scala