2011-03-30 32 views
12

Tôi muốn có một phương pháp mà trả về một lớp của một loại nhất định, nhưng tôi muốn phương pháp để hành xử khác nhau tuỳ thuộc vào việc hay không lớp kéo dài một đặc điểm đặc biệt như sau:Tôi có thể thực hiện đối sánh trên một tham số kiểu trong Scala để xem nó có thực hiện một đặc tính không?

 

case class ClassA extends TraitA 
case class ClassB extends TraitB 
case class ClassC extends TraitA 
... 
def myfunc[T]():T = { 
    T match { 
    case TraitA => // return new T in a particular way 
    case TraitB => // ditto 
    } 
} 
 

Đây có phải là có thể hoặc tôi đang đi sai đường?

Cảm ơn

Trả lời

13

Bạn không thể so sánh các loại trực tiếp, bởi vì không có gì để so sánh (khi chạy, do erasure). Bạn có thể làm việc trên một đại diện của lớp học của bạn:

trait TraitA { } 
trait TraitB { } 
class ClassA extends TraitA { } 
class ClassB extends TraitB { } 

def myFunc[T](clazz: Class[T]) = { 
    if (classOf[TraitA] isAssignableFrom clazz) println("A") 
    else if (classOf[TraitB] isAssignableFrom clazz) println("B") 
    else println("?") 
} 

scala> myFunc(classOf[ClassA]) 
A 

scala> myFunc(classOf[String]) 
? 

hoặc bạn có thể mô hình phù hợp trên trường hợp của lớp:

def myFunc2[T](t: T) = t match { 
    case _: TraitA => println("A") 
    case _: TraitB => println("B") 
    case _ => println("?") 
} 

scala> myFunc2(new ClassA) 
A 

scala> myFunc2(Some(5)) 
? 

Bạn cũng có thể sử dụng phương pháp tiếp cận đầu tiên trong một cách cú pháp ít gây khó chịu qua lớp biểu hiện:

def myFunc3[T](implicit mf: ClassManifest[T]) = { 
    val clazz = mf.erasure 
    if (classOf[TraitA] isAssignableFrom clazz) println("A") 
    else if (classOf[TraitB] isAssignableFrom clazz) println("B") 
    else println("?") 
} 

scala> myFunc3[ClassA] 
A 

scala> myFunc3[String] 
? 

và bạn có thể chọn các loại khác nhau của văn cũng nếu if/else trở thành wieldy:

object MyFunc { 
    val dispatch = Map(
    classOf[TraitA] -> (() => println("A")), 
    classOf[TraitB] -> (() => println("B")) 
) 
    val default =() => println("?") 
    def apply[T](implicit mf: ClassManifest[T]) = 
    dispatch.find(_._1 isAssignableFrom mf.erasure).map(_._2).getOrElse(default)() 
} 

scala> MyFunc[ClassA] 
A 

scala> MyFunc[String] 
? 

Lưu ý rằng bất kỳ mã chung nào mà bạn sử dụng mã này sẽ cần phải có sẵn tệp kê khai lớp (dưới dạng tham số ẩn hoặc viết tắt, [T: ClassManifest].

+0

Tôi thực sự tìm thấy 2 cách hoạt động tốt trong trường hợp của tôi: 1) classOf [TraitA] isAssignableTừ clazz như bạn đã đề xuất 2) if (mf <: codefly

+0

+1: lúc đầu tôi thấy khó chịu với cả câu trả lời và Scala ("Bạn không thể so sánh trực tiếp các loại, vì không có ** gì cả * * có để so sánh "... Có ** loại **, và một loại chắc chắn là một cái gì đó. Bạn nên viết" không có bất kỳ giá trị * * "IMHO). Nhưng sau đó bạn giải thích về các biểu hiện lớp học, và điều đó xảy ra tại chỗ. Cảm ơn! – rsenna

+0

@rsenna - Bởi "không có bất cứ điều gì" Tôi có nghĩa là không có bất cứ điều gì có _at runtime_ vì 'T' chỉ nói với trình biên dịch như thế nào nó nên giữ cho các loại của bạn ngay tại thời gian biên dịch. Vì vậy, thực sự ... một loại chung là, trong thời gian chạy, không có gì. Nó đi rồi. ("Loại tẩy xoá.") Tệp kê khai cung cấp một cách để cung cấp thông tin biên dịch thời gian đó khi chạy. ('ClassTag' hoặc' TypeTag' là cách mới để làm điều đó trong 2,10, mặc dù cách cũ vẫn hoạt động.) Dù sao, vui mừng bạn thấy nó hữu ích ngay cả khi cách nói của tôi không phải là rất lịch sự! –

1

Bạn cần một cá thể để kiểm tra loại. Bản thân nó chỉ là một trình giữ chỗ cho một loại. Bạn có thể làm một cái gì đó như thế này:

trait bTrait //common base trait 
trait TraitA extends bTrait 
trait TraitB extends bTrait 

class ClassA extends TraitA 
class ClassB extends TraitB 

def myFunc[T <: bTrait](t:T) : String = //passing explicitly an instance of type T 
{ 
    t match { 
    case _ : TraitA => "TraitA" 
    case _ : TraitB => "TraitB" 
    } 
} 

println(myFunc(new ClassA)) //prints TraitA 
+0

Đồng ý, nếu tôi có một trường hợp, điều này sẽ dễ dàng! – codefly

2

"muốn phương pháp để hành xử khác nhau tuỳ thuộc vào việc hay không lớp kéo dài một đặc điểm đặc biệt"

này gần như là một mô tả kinh điển của thừa kế. Bạn không thể có một phương pháp trong mỗi đặc điểm mà đóng gói các hành vi khác nhau bạn đang sau?

+0

Vấn đề chính ở đây là tôi không có một thể hiện của đối tượng. Dựa trên kiểu của đối tượng, tôi cần xác định nơi để đi và tìm nó (trong đó cơ sở dữ liệu trong trường hợp này) – codefly

Các vấn đề liên quan