2016-03-03 48 views
1

這將返回Any時:保持數據類型完好無損的比賽情況

def convertType(data: String, dataType: String) = { 
    dataType match { 
    case "Int" => data.toInt 
    case "Double" => data.toDouble 
    case "Long" => data.toLong 
    case "Option[Int]" => Some(data.toInt) 
    case "Option[Long]" => Some(data.toLong) 
    case "Option[Double]" => Some(data.toDouble) 
    } 
} 

// Isn't this a bad way to solve the problem ? 
implicit def anyToInt(str: Any) = str.asInstanceOf[Int] 
implicit def anyToLong(str: Any) = str.asInstanceOf[Long] 

val i: Int = convertType("1", "Int") 
val l: Long = convertType("1", "Long") 

什麼是保持原始數據類型完好的最佳方法?

+2

爲什麼不使用泛型? –

回答

0
import scala.reflect.runtime.universe._ 

    implicit class StringConverter(data: String) { 
    private[this] def convert(tag: Type): Any = tag match { 
     case t if t =:= typeOf[Int] => data.toInt 
     case t if t =:= typeOf[Double] => data.toDouble 
     case t if t =:= typeOf[Long] => data.toLong 
     case t if t =:= typeOf[Option[Int]] => Some(data.toInt) 
    } 
    def convert[T](implicit typeTag: TypeTag[T]): T = convert(typeTag.tpe).asInstanceOf[T] 
    } 
    scala> "123".convert[Int] 
    res5: Int = 123 

    scala> "123".convert[Option[Int]] 
    res6: Option[Int] = Some(123) 

    scala> "123".convert[Double] 
    res7: Double = 123.0 

正如@Luka Jacobowitz說,轉換類型與generics

  • implicit TypeTag與通用檢索類型信息
  • Type與案件的匹配分析數據
  • asInstanceOf投下變量目標類型(因爲它已經通過TypeTag進行檢查,因此可以安全地執行此操作)
0

你想做的事情有點棘手。如你所見,子類型不會得到你想要的,因爲必須返回所有返回類型的超類型。

雖然輸入變量,可能會挽救一天!

def convertType[T](x: String): T = x.asInstanceOf[T] 

但是,這不是你所需的東西......你需要的東西,有基於什麼T被傳遞不同的行爲。喜歡的東西(不是真正的Scala)

def convertType[T](x: String): T = T match { 
    case Double => x.toDouble 
    case Int => x.toInt 
    // And all your other cases 
} 

不幸的是Scala是不是一個完整的依賴性類型的語言,所以我們沒有,可以直接在類型的行爲,所以那場比賽語句不工作的功能。

但是,如果我們爲T類型提供了價值級「見證」,也許我們可以逃避我們的轉換。

def convertType[T](x: String)(witness: T): T = witness match { 
    case _: Double => x.toDouble 
    case _: Int => x.toInt 
    // Fill in other cases as necessary 
} 

我們可以把這個稍微爲自己方便的通過使證​​人implicit。現在只能讓我們在中途停下來,因爲我們仍然需要擁有奇怪的虛擬隱式值,除了作爲我們功能的證據外(例如隨機我們需要類似implicit val z = 2),我們不需要做任何事情。

我們可以擺脫創建這些虛擬值來傳入證人的需求嗎?

是的,有兩種方法。一種是使用Scala的TypeTags,它們確實是編譯器自動生成的類型的值級目擊者。

import scala.reflect.runtime.universe._ 

def convertTypes[T](x: String)(implicit witness: TypeTag[T]): T = witness match { 
    case a if a =:= typeOf[Int] => x.toInt 
    case a if a =:= typeOf[Double] => x.toDouble 
} 

或者,您可以將實際轉換移出到單獨的特徵並讓目擊者執行特徵指定的行爲。

trait Convertable[T] { 
    def convertFromString(x: String): T 
} 

implicit object ConvertInt extends Convertable[Int] { 
    override def convertFromString(x: String): Int = x.toInt 
} 

// Do the same for your other types 

def convertType[T](x: String)(implicit witness: Convertable[T]): T = witness.convertFromString(x) 

我們走吧!一個很好的類型安全ish轉換方法(至少這是最後一個)。如果您傳遞格式不正確的字符串,您可能希望將整個事件包裝在scala.util.Try中。

順便說一下,我們剛剛重新創建了typeclasses(或者使用了Scala的內置TypeTag類型類)。