Scala 使用类型参数def实现trait无法编译

Scala 使用类型参数def实现trait无法编译,scala,Scala,我想我可能用这个做了一些非常愚蠢的事情,但下面的代码片段并没有编译 scala> case class Foo1(i: Int) defined class Foo1 scala> trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] } defined trait Foo1 然后实现如下特征 scala> implicit val foodVal = new Foo1{ | def testFoo[Foo1](

我想我可能用这个做了一些非常愚蠢的事情,但下面的代码片段并没有编译

scala> case class Foo1(i: Int)
defined class Foo1

scala> trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
defined trait Foo1
然后实现如下特征

scala> implicit val foodVal = new Foo1{
 |       def testFoo[Foo1](l:List[Foo1] ) = {
 |         for{
 |           a <- l
 |           if (a.i == 1)
 |         } yield a
 |       }
 |     }
<console>:13: error: value i is not a member of type parameter Foo1

在REPL中,定义如下:

trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
正在替换类定义

case class Foo1(i: Int)
如果尝试使用“粘贴”命令执行相同的操作,您将看到无法同时定义这两者:

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Foo1(i: Int)
trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }


// Exiting paste mode, now interpreting.

<console>:36: error: Foo1 is already defined as case class Foo1
       trait Foo1{def testFoo[T](l1 : List[T] ) : List[T] }
             ^

要回答更新问题,答案是声明和实现之间的差异

当我以下面的形式编写参数化特征的实现时,我说的是“用具体类型
Foo
替换抽象类型
T

但是,当我重写一个由类型参数化的方法并更改该类型的名称时,我所做的只是为该抽象类型指定一个不同的名称。我不是指定要使用的特定具体类,而是指定一个新符号来标识我正在操作的抽象类型

trait Bar {
    def something[T](t: T) : T
}

val instance = new Bar {
    def something[Foo](t: Foo) : Foo = { ... }
}
因此,在上面的示例中,
Foo
不是一个具体的类型
Foo
,而
Foo
只是一个符号,表示将根据传递给方法的参数类型具体化的任意类型

因此,即使在同一范围内有一个名为
Foo
的具体类型,它也会被引入的类型参数
Foo
所遮蔽,并且在该方法的上下文中,对
Foo
的任何引用或
Foo
的实例都是对抽象类型参数
Foo
的引用,不是具体的类型
Foo

trait Bar[T] {...}

val instance = new Foo[Bar] { ... }
  • 您必须以不同的形式为trait和case类命名,因为两种类型不能具有相同的名称。(Mike已经解释过,为什么要用REPL编译)

  • def testFoo[Foo1](l:List[Foo1])={
    行中,
    Foo1
    是一个新的泛型类型参数,而不是您的案例类的类型
    Foo1

  • (IMHO)用类型注释隐式val总是一个好主意

  • 也就是说,下面是您需要的代码:

    case class Foo1(i: Int)
    
    trait Foo2 {
      type T
    
      def testFoo(l1 : List[T] ) : List[T]
    }
    
    implicit val foodVal: Foo2 = new Foo2 {
      type T = Foo1
    
      def testFoo(l: List[T]) = {
        for { a <- l if a.i == 1 } yield a
      }
    }
    
    通过
    this访问完成示例。

    class Bar[T] {
      type Inner = T
      def func[Inner](t: Inner) = {
        // won't compile because the "Inner" type of the class is initialized with T
        val test: this.Inner = t
      }
    }
    

    如果你不进一步指定类型参数,它可以是
    任何
    (东西)。如果你需要一个带有特定API的类型。你需要告诉编译器,使用
    你的第一个示例不会像写的那样工作,因为类型t@SaschaKolberg谢谢。我更新了我的问题。你介意在“更新”中解释这个问题吗部分?谢谢。我更新了我的问题。你介意在“更新”中解释问题吗部分?添加了一个更新,希望能够解决您的问题。顺便说一句,一个单独的问题可能会更好,因为未来的读者和搜索答案的人在阅读多个问题和答案的更新时很难弄清楚发生了什么。
    
    case class Foo1(i: Int)
    
    trait Foo2 {
      type T
    
      def testFoo(l1 : List[T] ) : List[T]
    }
    
    implicit val foodVal: Foo2 = new Foo2 {
      type T = Foo1
    
      def testFoo(l: List[T]) = {
        for { a <- l if a.i == 1 } yield a
      }
    }
    
    class Foo(arg: Int) {
      val field: Int = 1
    
      def func(field: String) = {
        // here field will always refer to the function paramter
        // if you want to access the class field you would have to call this.field
      }
    }
    
    class Bar[T] {
      def func[T](t: T) = {
        // within the scope of the function T IS NOT "Bar#T".
        // However, you cannot access the class type parameter with "this.T" in this example 
      }
    
      def func2(t: T) = {
        // here T is the classes type parameter T
      }
    }
    
    class Bar[T] {
      type Inner = T
      def func[Inner](t: Inner) = {
        // won't compile because the "Inner" type of the class is initialized with T
        val test: this.Inner = t
      }
    }
    
    trait Api {
      def func: String
    }
    
    def func[T <: Api](arg: T) = {
      arg.func // yay
    }