首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Scala中,如何告诉抽象基类类型参数T支持Int (或Float,或...)的隐式转换?

在Scala中,如何告诉抽象基类类型参数T支持Int (或Float,或...)的隐式转换?
EN

Stack Overflow用户
提问于 2012-02-12 09:45:06
回答 3查看 1.7K关注 0票数 4

我很难从C++/模板的世界过渡到scala。我习惯于在模板参数T上使用我想要的任何操作,只要我用来实例化T的任何东西都支持这些操作(基本上是编译时Duck类型)。我在Scala中找不到相应的习惯用法,它允许我定义一个只有一个类型参数的抽象类,并期望为类型T提供一个特定的接口。

我所拥有的几乎可以工作,但是我不知道如何告诉抽象类(Texture[T <:SummableT]) T支持从Int转换/构造。如何将隐式转换添加到特征可求和中,以便纹理知道T支持该转换?

代码语言:javascript
复制
trait Summable[T] { 
   def += (v : T) : Unit
   def -= (v : T) : Unit   
}

object Int4 { implicit def int2Int4(i : Int) = new Int4(i, i, i, i) }

class Int4 (var x : Int, var y : Int, var z : Int, var w : Int) extends Summable[Int4] {
   def this (v : Int) = this(v, v, v, v)
   def += (v : Int4) : Unit = { x += v.x; y += v.y; z += v.z; w += v.w }
   def -= (v : Int4) : Unit = { x -= v.x; y -= v.y; z -= v.z; w -= v.w } 
}

abstract class Texture[Texel <: Summable[Texel]] {
   var counter : Texel
   def accumulate(v : Texel) : Unit = { counter += v }
   def decrement() : Unit = { counter -= 1 } //< COMPILE ERROR HERE, fails to find implicit
}

class Int4Target extends Texture[Int4] {
   var counter : Int4 = new Int4(0, 1, 2, 3)
}
EN

回答 3

Stack Overflow用户

发布于 2012-02-12 10:41:43

您可以像这样定义隐式构造函数参数

代码语言:javascript
复制
abstract class Texture[Texel <: Summable[Texel]](implicit int2Texel: Int => Texel) {
//...

这实际上告诉编译器,为了构造Texture的实例,必须有一个从IntTexel的隐式转换函数。假设您已经在作用域中的某个地方定义了这样一个函数(确实如此),您应该不会再收到编译错误。

Edit2:好的,我最初误解了你的代码,你实际上只需要一个来自Int => Texel的隐式参数。您的代码通过上述修改为我进行了编译。

编辑:您实际上需要2个转换函数,一个来自Texel => Int,另一个来自Int => Texel,以便正确地重新分配变量

票数 4
EN

Stack Overflow用户

发布于 2012-02-12 15:12:49

C++模板与Scala中的任何模板之间的一个基本区别是,C++模板是针对每次使用而编译的--也就是说,如果将一个模板与intdouble一起使用,则会编译两个不同的类,并且只有在某些代码实际使用它时才会编译它们。

另一方面,Scala有单独的编译。考虑到JVM的局限性,它不如Java的好,但仍然遵循基本原则。所以,如果某个东西有一个类型参数,它仍然是在声明时编译的,并且只有一个这样的类存在。编译后的代码必须支持所有可能的参数,而不是可以调用的参数,这就造成了与模板截然不同的限制。

关于特征和隐式转换,特征不支持参数,而隐式转换(视图边界)是参数。取而代之的是使用类。

票数 3
EN

Stack Overflow用户

发布于 2012-02-12 10:25:34

在scala中,不可能要求特征的类型参数存在隐式转换。这是有充分理由的。假设我们定义了如下特征:

代码语言:javascript
复制
trait ATrait[T <% Int] {
    def method(v: T) { println(v: Int) }
}

然后在两个地方制作了它的实例:

代码语言:javascript
复制
package place1 {
    implicit def strToInt(s: String) = 5
    val inst = new ATrait[String]
}

package place2 {
    implicit def strToInt(s: String) = 6
    val inst = new ATrait[String]
}

然后使用这些实例,如:

代码语言:javascript
复制
val a = if (someTest) place1 else place2
a.method("Hello")

应该打印5还是6?也就是说,它应该使用哪种隐式转换?必须在编译时找到隐式转换,但您不知道在创建对象时存在哪个隐式转换。

换句话说,隐式是由使用它们的作用域提供的,而不是由使用它们的对象提供的;后者是不可能的。

那么,关于你的问题。您可以使用普通成员而不是隐式成员:

代码语言:javascript
复制
trait Summable[T] { 
   def -= (v: T): Unit
   def -= (v: Int) { this -= (encode(v)) }

   def encode(i: Int): T
}

class Int4 (var x: Int, var y: Int, var z: Int, var w: Int) extends Summable[Int4] {
   def -= (v : Int4) : Unit = { x -= v.x; y -= v.y; z -= v.z; w -= v.w } 

   def encode(i: Int) = Int4.int2Int4(i)
}

现在decrement方法可以正确编译了。

另一种说法是,不要将隐式视为属于某个类型的属性(即,“可以从Int隐式转换”不是Int4的属性)。它们是值,可以使用类型进行标识。

希望这能有所帮助。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9245717

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档