2016-12-02 17 views
0

我試圖支持框架的ID類型的抽象。例如這裏:Scala中基本類型的可選轉換

object AmINecessary { 
    case class StringConverter[T](op: String => T) 
    implicit val toInt = new StringConverter[Int](_.toInt) 
    implicit val toLong = new StringConverter[Long](_.toLong) 
} 

class Foo[ID] { 
    // ID can be String, Long, or Int 
    import AmINecessary._ 
    // If ID is string, return string, otherwise convert to ID 
    def getID(id: String)(implicit c: StringConverter[ID] = null): ID = if (c == null) id.asInstanceOf[ID] else c.op(id) 
} 

這隨後被用作:

val fooString = new Foo[String] 
val fooLong = new Foo[Long] 
val fooInt = new Foo[Int] 


fooString.getID("asdf") // "asdf":String 
fooLong.getID("1234") // 1234:Long 
fooInt.getID("1234") // 1234:Int 
fooInt.getID("asdf") // java.lang.NumberFormatException 

可正常工作。我的問題是:

  1. 使用可選的隱含通過默認爲null,然後分支上感覺。什麼是scala方式來實現這一點?
  2. 真的有必要寫一個字符串的隱式轉換爲long或int嗎?

回答

1

我認爲最好的選擇是簡單地添加一個隱含的StringConverter[String]並刪除默認的null值。 這樣你的fooString的工作沒有冒任何其他類型ClassCastException

object AmINecessary { 
    case class StringConverter[T](op: String => T) 
    implicit val toInt = new StringConverter[Int](_.toInt) 
    implicit val toLong = new StringConverter[Long](_.toLong) 
    implicit val idConverter = new StringConverter[String](identity) 
} 

class Foo[ID] { 
    import AmINecessary.StringConverter 

    def getID(id: String)(implicit c: StringConverter[ID]): ID = c.op(id) 
} 

關於你的問題2,類型類的方法是不是真的必要(但要注意,有沒有隱式轉換這裏)。你也可以這樣做:

abstract class Foo[ID] { 
    def getID(id: String): ID 
} 

class FooInt extends Foo[Int] { 
    def getID(id: String) = id.toInt 
} 

class FooLong extends Foo[Long] { 
    def getID(id: String) = id.toLong 
} 

class FooString extends Foo[String] { 
    def getID(id: String) = id 
} 
+0

第二個例子是我在與implicits戰鬥後最終做了什麼。不覺得好,​​但比隱含的混亂和作品更好。 – rapidninja

0

1)關於隱含默認爲空,你可以只:

object Unsafe { 
    implicit val toT[T] = new StringConverter[T](_.asInstanceOf[T]) 
} 

2)它似乎不是一個好主意呢。首先,因爲你隱藏了asInstanceOf,這是不安全的操作(潛在的運行時異常)。其次,更明確的轉換是 - 更好。

如果你期待一些複雜的轉換 - 這是更好地從你的getID方法返回選項:

def getId[T](id: String)(converter: Option[StringConverter] = None) = converter.map(_.op(id)) 

然而,默認參數是不是最好的方法要麼。一般來說,我會堅持編譯時錯誤,要求用戶編寫自己的轉換器或明確地執行asInstanceOf

在您的具體情況asInstanceOf沒有多大意義,因爲只有它會爲工作類型爲字符串,如getId[String],所以什麼叫getId然後點?

+0

空轉換器的想法:只有三種可能的ID類型。當我嘗試添加一個StringToString時,它懷疑模糊的分辨率。出於某種原因,Jasper-M的版本有效,不知道爲什麼我的原始嘗試沒有。 – rapidninja