我有以下简单的演示代码,它给出了类型不匹配错误。 我完全不明白为什么会发生这种错误。有人会告诉我如何解决这个错误。进一步解释或相关的学习资源将非常感谢。
object Application extends App {
private val foo = new Foo
private val holder = new FooTypeHolder
private val client = new Client(holder)
client.showElementType(foo)
}
class Foo
trait TypeHolder[T] {
type ElementType = T
}
class FooTypeHolder extends TypeHolder[Foo]
class Client[T <: TypeHolder[_]](val holder: T) {
def showElementType(t: T#ElementType): Unit = {
println("show element type " + t.toString)
println(t.getClass)
}
}
编译错误为:
Error:(10, 26) type mismatch;
found : Application.foo.type (with underlying type Foo)
required: _$1
client.showElementType(foo)
就像Andrey Tyukin对TypeHolder
用于什么感到好奇一样,它只包含T
之外的任何内容。我在这个特性上添加了一些功能。
代码如下。
object Application extends App {
private val foo = new Foo
private val holder = new FooTypeHolder
private val client = new Client(holder)
client.showElementType(foo)
}
class Foo
trait TypeHolder[T] {
type ElementType = T
def holderFun(): Unit = println(s"holder, type:${getClass}")
def elementFun(ele: ElementType): Unit = println(s"element, type:${getClass}")
}
class FooTypeHolder extends TypeHolder[Foo]
class Client[T <: TypeHolder[_]](val holder: T) {
def showElementType(t: T#ElementType): Unit = {
println("show element type " + t.toString)
holder.holderFun()
holder.elementFun(t)
}
}
给出如下编译错误:
Error:(10, 26) type mismatch;
found : o2.Application.foo.type (with underlying type o2.Foo)
required: _$1
client.showElementType(foo)
Error:(30, 23) type mismatch;
found : _$1
required: Client.this.holder.ElementType
(which expands to) _$1
holder.elementFun(t)
总的来说,我想知道的核心是:
当我通过client
实例化val client = new Client(holder)
时
而holder
的类型为:TypeHolder[Foo]
scala编译器是否可以推断ElementType
的{{1}}是“hoder
”?
非常感谢@Andrey提供各种可行的解决方案。 我检查你的代码片段1~3,并仔细比较我的代码,这让我现在更清楚了。不过我还有一些问题。
此版本的代码最接近我的原始邮政编码。唯一的区别是函数Foo
showElementType
def showElementType(t: T#ElementType): Unit
让我感到困惑的是,因为“def showElementType(t: holder.ElementType): Unit
”有效,“(t: holder.ElementType)
”也应该有用吗?事实上并非如此。为什么呢?
这里的区别是(t: T#ElementType)
的位置。我把它放在特征定义中,而你把它放在类型参数限制中。
type ElementType = T
trait TypeHolder[T] { type ElementType = T}
我无法理解为什么特质定义中的赋值语句不起作用。
您使用两个类型参数class Client[T, H <: TypeHolder { type ElementType = T }]
&amp; T
分别捕获H
和Foo
的类型。它应该绝对有效。客户端的类型也与TypeHolder
相对应。我的问题是,是否可以定义客户端只使用一个类型参数,例如Client[Foo, TypeHolder[Foo]]
。换句话说,编译器是否可以从Client[TypeHolder[Foo]]
推断TypeHolder[Foo]
是ElementType
?
谢谢。
答案 0 :(得分:2)
经过一些修改后编译:
object Application extends App {
private val foo = new Foo
private val holder = new FooTypeHolder
private val client = new Client(holder)
// not sure why you try to use this one
// client.showElementType(foo)
// foo doesn't extend the Typeholder, it's just regular class
// on the other hand this will compile
client.showElementType(holder)
}
class Foo
trait TypeHolder[T] {
type ElementType = T
}
class FooTypeHolder extends TypeHolder[Foo]
class Client[T <: TypeHolder[_]](val holder: T) {
// no need to use the #ElementType
def showElementType(t: T): Unit = {
println("show element type " + t.toString)
println(t.getClass)
}
}
希望这也有帮助:
What does the `#` operator mean in Scala?
https://github.com/ghik/opinionated-scala/wiki/Generics-and-type-members
就错误_ $ 1而言,它只是编译器说:&#34;我无法解决这个问题&#34;
答案 1 :(得分:2)
我不确定你在这里尝试了什么,但这里是我的版本&#34;可能最接近的代码投影到可编辑的Scala&#34;:
import scala.language.higherKinds
object Application extends App {
private val foo = new Foo
private val holder = new FooTypeHolder
private val client = new Client(holder)
client.showElementType(foo)
}
class Foo
trait TypeHolder[T] {
type ElementType = T
}
class FooTypeHolder extends TypeHolder[Foo]
class Client[T, H[X] <: TypeHolder[X]](val holder: H[T]) {
def showElementType(t: T): Unit = {
println("show element type " + t.toString)
println(t.getClass)
}
}
但也可能是这样:
import scala.language.higherKinds
object Application extends App {
private val foo = new Foo
private val holder = new FooTypeHolder
private val client = new Client[Foo, FooTypeHolder](holder)
client.showElementType(foo)
}
class Foo
trait TypeHolder {
type ElementType
}
class FooTypeHolder extends TypeHolder {
type ElementType = Foo
}
class Client[T, H <: TypeHolder { type ElementType = T }](val holder: H) {
def showElementType(t: T): Unit = {
println("show element type " + t.toString)
println(t.getClass)
}
}
或者这个?:
import scala.language.higherKinds
object Application extends App {
private val foo = new Foo
private val holder = new FooTypeHolder
private val client = new Client(holder)
client.showElementType(foo)
}
class Foo
trait TypeHolder[T] {
type ElementType = T
}
class FooTypeHolder extends TypeHolder[Foo]
class Client[H <: TypeHolder[_]](val holder: H) {
def showElementType(t: holder.ElementType): Unit = {
println("show element type " + t.toString)
println(t.getClass)
}
}
我从根本上不了解你的代码是:TypeHolder[T]
应该做什么,究竟是什么?整个TypeHolder[T]
构造似乎不包含T
以外的任何信息,为什么不直接使用T
,这样?:
object Application extends App {
private val foo = new Foo
private val client = new Client[Foo]
client.showElementType(foo)
}
class Foo
class Client[T] {
def showElementType(t: T): Unit = {
println("show element type " + t.toString)
println(t.getClass)
}
}
一些一般提示:
修改强>
我只是尝试以与您已将其添加到您的帖子中的顺序相同的顺序回答所有其他问题:
1。它适用于holder.ElementType
,因为当您实例化Client
时,holder
已知为TypeHolder[Foo]
类型,因此我们知道holder.ElementType = Foo
。
2。它对T#ElementType
的{{1}}不起作用,因为正如签名中的存在主义所说,T <: TypeHolder[_]
可以是{{1} } T
未指定TypeHolder
:
forSome
因此ElementType
被设置为一些奇怪的合成存在类型T <: TypeHolder[_$1] forSome { type _$1 }
T#ElementType
= (TypeHolder[_])#ElementType
= (TypeHolder[_$1] forSome { type _$1 })#ElementType
= _$1
,并且您得到的错误消息看起来有点像这样:
T#ElementType
因此,将其设置为存在类型是完全无用的,您将永远无法找到满足此奇怪类型约束的术语。你甚至不能强行转换为这种类型,因为这种类型甚至没有一个名称可以在代码中的任何地方引用它。
说实话:这似乎完全是垃圾。整个预测根本不应该编译,为什么世界上任何人都希望存在量化的类型从量词下逃脱?这可能应该报告为编译器问题。
3. 定义
_$1
有效,因为它还保持类型typeHolder.scala:6: error: type mismatch;
found : Main.foo.type (with underlying type Foo)
required: _$1
client.showElementType(foo)
^
显式。如果你更换它
由存在主义
class Client[T, H <: TypeHolder { type ElementType = T }]
然后,T
和class Client[T, H <: TypeHolder { type ElementType = X forSome { type X }}]
之间的每个连接都会丢失,并且会因上述T
的原因而失败:您无法替换元素类型由一些未知的存在主义,然后希望能够将TypeHolder
传递给它。
4. On&#34;是否可以定义客户端只使用一个类型参数?&#34; - 当然,为什么不呢?
T#ElementType
不要将任何类型参数添加到Foo
,因此您不必在以后通过存在来删除它们。