簡體   English   中英

使用泛型參數運行函數而不使用asInstanceOf

[英]Run function with generic parameter without using asInstanceOf

這是我的示例scala代碼:

object App {
  abstract class BaseAction
  type ApiAction[T <: BaseAction] = (T) => Unit

  case class FirstAction(name: String) extends BaseAction
  case class SecondAction(surname: String) extends BaseAction

  def action1[Z <: BaseAction] = {  
    (a: Z) => { // Here i'would like to have a: FirstAction
      val z = a.asInstanceOf[FirstAction]
      println("Running action: " + z.name )
    }
   }

 def action2[Z <: BaseAction] = {
  (a: Z) => { // Here i'would like to have a: SecondAction
  val z = a.asInstanceOf[SecondAction]
  println("Running action " + z.surname )
 }
}

  def myActions[T <: BaseAction] = Map[String, ApiAction[T]]("a1" -> action1[T], "a2" -> action2[T])

  myActions("a1")(FirstAction("Action 1"))
  myActions("a2")(SecondAction("Action 2"))
}

我有很少的動作功能,它們做了不同的事情。 每個動作函數都接收一個參數:action class,其中所有動作類都繼承自BaseAction抽象類。

函數myActions是actionName到action函數的Map。

我的代碼正在運行,但我認為使用asInstanceOf並不是一個好習慣,我想知道如何只使用泛型類型編寫此代碼,而不使用asInstanceOf。

問題是你做了很多“你不應該做這些事情”。

我將嘗試給你“更好”(按照大多數scala人)的方式來寫同樣的東西。 這些更改包括使用來自類型邊界的信息以及自定義類型ApiAction來編寫更可預測和有組織的代碼。

首先你有以下抽象,

  abstract class BaseAction

  type ApiAction[T <: BaseAction] = (T) => Unit

  case class FirstAction(name: String) extends BaseAction
  case class SecondAction(surname: String) extends BaseAction

現在您可以使用這些抽象來編寫您的Actions對象,

object MyActions {

  val action1: ApiAction[FirstAction] = {
    case FirstAction(name) => println("Running action :: " + name)
  }

  val action1Other: ApiAction[FirstAction] = (fa: FirstAction) => {
    println("Running action :: " + fa.name)
  }

  val action2: ApiAction[SecondAction] = {
    case SecondAction(surname) => println("Running action :: " + surname)
  }

  val action2Other: ApiAction[SecondAction] = (sa: SecondAction) => {
    println("Running action :: " + sa.surname)
  }

  // but lets say you wanted a generic ApiAction
  val actionGeneric: ApiAction[BaseAction] = {
    case FirstAction(name) => println("Running action :: " + name)
    case SecondAction(surname) => println("Running action :: " + surname)
  }

}

現在,您可以在應用中使用這些“操作”,

object MyApp extends App {

  MyActions.action1(FirstAction("Action 1"))

  MyActions.action1Other(FirstAction("Action 1 Other"))

  MyActions.actionGeneric(FirstAction("Action 1 Generic"))

  MyActions.action2(SecondAction("Action 2"))

  MyActions.action2Other(SecondAction("Action 2 Other"))

  MyActions.actionGeneric(SecondAction("Action 2 Generic"))
}

您可以使用慣用的Scala模式匹配而不是asInstanceOf

val z = a match {
  case FirstAction(name) => println("Running action " + name)
  case _ => println("Error")
}

請注意,模式匹配仍然使用isInstanceof + asInstanceOf ,但它被認為是一種很好的做法,不像直接調用asInstanceOf

順便說一下,組織你的代碼可能是明智的,這樣你只匹配一次,而不是有兩個單獨的“第一個動作或錯誤”和“第二個動作或錯誤”塊:

def action[Z <: BaseAction] = {
  (a: Z) => a match {
    case FirstAction(name) => println("Running action " + name)
    case SecondAction(surname) => println("Running action " + surname)
    case _ => println("Error")
  }
}

def myActions[T <: BaseAction] = Map[String, ApiAction[T]]("a1" -> action[T], "a2" -> action[T])

myActions("a1")(FirstAction("Action 1"))
myActions("a2")(SecondAction("Action 2"))

// output:
// Running action Action 1
// Running action Action 2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM