我很难从C++/模板的世界过渡到scala。我习惯于在模板参数T上使用我想要的任何操作,只要我用来实例化T的任何东西都支持这些操作(基本上是编译时Duck类型)。我在Scala中找不到相应的习惯用法,它允许我定义一个只有一个类型参数的抽象类,并期望为类型T提供一个特定的接口。
我所拥有的几乎可以工作,但是我不知道如何告诉抽象类(Texture[T <:SummableT]) T支持从Int转换/构造。如何将隐式转换添加到特征可求和中,以便纹理知道T支持该转换?
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)
}发布于 2012-02-12 10:41:43
您可以像这样定义隐式构造函数参数
abstract class Texture[Texel <: Summable[Texel]](implicit int2Texel: Int => Texel) {
//...这实际上告诉编译器,为了构造Texture的实例,必须有一个从Int到Texel的隐式转换函数。假设您已经在作用域中的某个地方定义了这样一个函数(确实如此),您应该不会再收到编译错误。
Edit2:好的,我最初误解了你的代码,你实际上只需要一个来自Int => Texel的隐式参数。您的代码通过上述修改为我进行了编译。
编辑:您实际上需要2个转换函数,一个来自Texel => Int,另一个来自Int => Texel,以便正确地重新分配变量
发布于 2012-02-12 15:12:49
C++模板与Scala中的任何模板之间的一个基本区别是,C++模板是针对每次使用而编译的--也就是说,如果将一个模板与int和double一起使用,则会编译两个不同的类,并且只有在某些代码实际使用它时才会编译它们。
另一方面,Scala有单独的编译。考虑到JVM的局限性,它不如Java的好,但仍然遵循基本原则。所以,如果某个东西有一个类型参数,它仍然是在声明时编译的,并且只有一个这样的类存在。编译后的代码必须支持所有可能的参数,而不是可以调用的参数,这就造成了与模板截然不同的限制。
关于特征和隐式转换,特征不支持参数,而隐式转换(视图边界)是参数。取而代之的是使用类。
发布于 2012-02-12 10:25:34
在scala中,不可能要求特征的类型参数存在隐式转换。这是有充分理由的。假设我们定义了如下特征:
trait ATrait[T <% Int] {
def method(v: T) { println(v: Int) }
}然后在两个地方制作了它的实例:
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]
}然后使用这些实例,如:
val a = if (someTest) place1 else place2
a.method("Hello")应该打印5还是6?也就是说,它应该使用哪种隐式转换?必须在编译时找到隐式转换,但您不知道在创建对象时存在哪个隐式转换。
换句话说,隐式是由使用它们的作用域提供的,而不是由使用它们的对象提供的;后者是不可能的。
那么,关于你的问题。您可以使用普通成员而不是隐式成员:
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的属性)。它们是值,可以使用类型进行标识。
希望这能有所帮助。
https://stackoverflow.com/questions/9245717
复制相似问题