使用类型参数def实现特征无法编译

时间:2015-08-22 14:13:17

标签: scala

我想我可能会做一些非常愚蠢的事情,但是以下代码片段无法编译。

trait

然后实施以下特征

def

更新 谢谢你的回复。我真的很想了解在scala> trait Bar { def testFoo[T](l1: List[T] ) : List[T] } defined trait Bar scala> implicit val fooVal = new Bar { | override def testFoo[Foo1](l:List[Foo1]) : List[Foo1] = { | for { a <- l if a.i == 1} yield a | } | } <console>:18: error: value i is not a member of type parameter Foo1 级与{{1}}级别传递类型之间的区别。在答案中,我可以看到类型是在一个特征级别传递,它确实有效但后面仍然给我相同的错误

{{1}}

2 个答案:

答案 0 :(得分:4)

在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] }
             ^

因此,你需要使用与你的案例类不同的特征名称,这是明智的,因为它们指的是不同的东西。

重新命名后,有几种方法可以实现目标。一个由Sascha概述(使用类型成员),或者您可以提升类型T来参数化您的特征,而不是在特征上参数化方法。

case class Foo1(i: Int)

trait Bar[T] {
  def testFoo(l1 : List[T] ) : List[T]
}

implicit val foodVal: Bar[Foo1] = new Bar[Foo1] {
  override def testFoo(l: List[Foo1]): List[Foo1] = {
    for { a <- l if a.i == 1 } yield a
  }
}

要回答更新问题,答案是声明和实施之间的区别。

当我在下面的表单中编写参数化特征的实现时,我说&#34;将抽象类型T替换为具体类型Foo&#34;。

trait Bar[T] {...}

val instance = new Foo[Bar] { ... }

但是当我覆盖一个按类型参数化并更改类型名称的方法时,我所做的就是为该抽象类型指定一个不同的名称。我没有指定要使用的具体具体类,我指定了一个新符号来识别我正在操作的抽象类型。

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

答案 1 :(得分:3)

  1. 您必须将 trait 案例类命名为彼此不同,因为两种类型的名称不能相同。 (Mike已经解释过,为什么它在REPL中编译)

  2. (select d.* from data d where recorded_at > '2015-01-01 01:01:01' order by recorded_at limit 1 ) union all (select d.* from data d where recorded_at > '2015-02-01 01:01:01' order by recorded_at limit 1 ) 行中,def testFoo[Foo1](l: List[Foo1]) = {是新的通用类型参数, 案例类的类型 {{ 1}}。

  3. (恕我直言)用类型注释隐式val总是一个好主意。

  4. 那就是说,这里是应该做的代码,你想要的是什么:

    Foo1

    更新(回答问题更新):

    类型参数,尤其是命名参数,与常用参数非常相似。是否访问类参数或具有相同名称的函数参数的关键是范围

    Foo1

    要完成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
      }
    }
    

    如果您未进一步指定类型参数,则可以是this.(事物)。如果您需要具有特定API的类型。您需要使用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 } } 运算符告诉编译器。

    Any

    这称为upper type bound。有许多任意复杂的方法来细化类型参数,您必须阅读文档。