2012-02-12 1 views
4

C++/Templates의 세계에서 scala로 전환하는 데 어려움을 겪고 있습니다. 템플릿 매개 변수 T에서 원하는 작업을 사용할 수있는 데 익숙합니다. T를 인스턴스화하는 데 사용하는 모든 작업 (기본적으로 컴파일 타임에 Duck typing)을 지원하는 한 사용할 수 있습니다. 스칼라에서 단일 유형 매개 변수로 추상 클래스를 정의 할 수 있고 T 유형의 특정 인터페이스를 예상하는 해당 관용구를 찾을 수 없습니다.스칼라에서 형식 매개 변수 T가 Int (또는 Float, 또는 ...)에서 암시 적 변환을 지원한다는 추상 기본 클래스를 어떻게 말할 수 있습니까?

거의 작동하지만 어떻게 작동하는지 알 수 없습니다. T가 Int에서 변환/생성을 지원한다는 추상 클래스 (Texture [T < : Summable [T]])를 말하십시오. 내재적 변환을 Summit 특성에 추가하여 T가 변환을 지원한다는 것을 Texture가 알 수 있도록하려면 어떻게해야합니까?

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) 
} 

답변

2

스칼라 형질 유형 파라미터에 존재하는 암시 적 변환을 필요로하는 것은 불가능하다. 이것에 대한 좋은 이유가 있습니다. 우리가 정의한다고 가정처럼 특성 :

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? 즉, 암시 적 변환을 사용해야합니까? 컴파일시 Implicits를 찾아야하지만 개체 생성시 암시 적으로 변환이 있는지 여부를 알 수 없습니다.

즉, 암시는 사용 된 개체에 의해 이 아닌 사용 된 범위로 제공됩니다. 후자는 불가능할 것이다.

문제에 대해.

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 방법은 제대로 컴파일 대신 암시를 사용하여, 당신은 일반 멤버를 사용할 수 있습니다.

또 다른 방법은 implicits를 유형에 속하는 속성으로 생각하지 마십시오 (즉, "암시 적으로 Int에서 변환 될 수 있음"은 Int4의 속성이 아닙니다). 값은 유형을 사용하여 식별 할 수있는 값입니다.

희망이 도움이됩니다.

+2

본인은 형질에 대한 암시에 대한 귀하의 이의 제기를 따르지 않습니다. 형질에 대한 함축성은 형질을 지탱하지 못하기 때문에 가능하지 않다. 클래스는 여기에 요청 된 것과 같은 것을 포함하여 종종 함축을 가질 수 있고, 그렇게 할 수 있습니다 - 클래스는 왜 그것을 가지지 만 특성 (생성자가 부족한 것 외에는)을 가질 수 없습니까? –

+0

@ 대니얼 정확히. 클래스에는 생성자가 있으므로 암시 적 매개 변수가되므로 멤버가됩니다. 특성으로 모든 구성원이 명시 적으로 선언됩니다. 근본적으로 요점은 구성원이 없으면 암시 적 값을 전달할 수 없으므로 [T <% S]와 같이 서명에 나타날 수 없다는 것입니다. 그리고 암시 적 매개 변수가있는 클래스조차도 클래스의 인스턴스를 사용하는 사람들은 자동으로 범위에 포함되지 않습니다. – Owen

4

당신이 본질적으로 Texture의 인스턴스를 생성하기 위해, Int에서 Texel 사용할 수 암시 적 변환 기능이 있어야 컴파일러를 알려줍니다이

abstract class Texture[Texel <: Summable[Texel]](implicit int2Texel: Int => Texel) { 
//... 

같은 암시 적 생성자 매개 변수를 정의 할 수 있습니다. 범위에서 어딘가에 정의 된 함수가 있다고 가정하면 더 이상 컴파일 오류가 발생하지 않아야합니다.

편집 2 : 원래 코드를 잘못 읽었으므로 실제로 암시 적 매개 변수는 Int => Texel에서 하나만 필요합니다.위 코드를 수정하면 코드가 컴파일됩니다.

편집 : 당신은 실제로 제대로

3

는 C++ 템플릿과 스칼라에서 아무것도 사이의 근본적인 차이는 C++ 템플릿이 컴파일되어 있다는 VAR를 재 할당하기 위해 2 개 변환 기능, Int => Texel에서 Texel => Int에서, 다른 하나가 필요합니다 각 사용 - intdouble이있는 템플릿을 사용하면 두 개의 다른 클래스가 컴파일되고 실제로 일부 코드가 실제로 사용할 때 컴파일됩니다.

스칼라는 다른 컴파일을 가지고 있습니다. 자바의 한계를 감안할 때 자바만큼 좋지는 않지만 여전히 기본 원칙을 따른다. 그래서, 어떤 것이 타입 매개 변수를 가지고 있다면, 그것은 선언시에 컴파일되고, 그런 클래스는 오직 하나만 존재합니다. 컴파일 된 코드는 호출 할 수있는 것보다 가능한 모든 매개 변수를 지원해야하므로 템플릿과는 다른 제한이 있습니다.

특성 및 암시 적 변환의 측면에서 특성은 매개 변수를 지원하지 않으며 암시 적 변환 (보기 범위)은 매개 변수입니다. 대신 클래스를 사용하십시오.

관련 문제