Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala:类型推断缺少某些内容_Scala_Type Inference_Type Safety - Fatal编程技术网

Scala:类型推断缺少某些内容

Scala:类型推断缺少某些内容,scala,type-inference,type-safety,Scala,Type Inference,Type Safety,我希望在以下情况下实现某种类型的安全性 基本上,我有不同类型的请求存储在数据库中,它们的类型由一些字符串代码标识。出于业务原因,此代码与类名不匹配 每种类型的请求都包括某种类型的有效负载,有效负载的类型直接取决于请求的类型 以下是我迄今为止所取得成就的简化版本: trait Request[Payload] { def metadata: String // Not relevant def payload: Payload } case class RequestWithString

我希望在以下情况下实现某种类型的安全性

基本上,我有不同类型的请求存储在数据库中,它们的类型由一些字符串代码标识。出于业务原因,此代码与类名不匹配

每种类型的请求都包括某种类型的有效负载,有效负载的类型直接取决于请求的类型

以下是我迄今为止所取得成就的简化版本:

trait Request[Payload] {
  def metadata: String // Not relevant
  def payload: Payload
}

case class RequestWithString(override val metadata: String, override val payload: String) extends Request[String]

case class AnotherTypeOfRequestWithString(override val metadata: String, override val payload: String) extends Request[String]

case class RequestWithInt(override val metadata: String, override val payload: Int) extends Request[Int]

object Request {
  def apply(code: String)(metadata: String, payload: Any): Request[_] = code match {
    case "S" => RequestWithString(metadata, payload.asInstanceOf[String])
    case "S2" => AnotherTypeOfRequestWithString(metadata, payload.asInstanceOf[String])
    case "I" => RequestWithInt(metadata, payload.asInstanceOf[Int])
  }
}
这并不令人满意,因为我希望Scala推断有效负载的类型以避免强制转换,以及返回值的(参数化)类型

我要找的是这样的东西:

object Request {
  def apply[P, R <: Request[P]](code: String)(metadata: String, payload: P): R = code match {
    case "S" => RequestWithString(metadata, payload)
    case "S2" => AnotherTypeOfRequestWithString(metadata, payload)
    case "I" => RequestWithInt(metadata, payload)
  }
}

在这种情况下,Scala不应该推断p是字符串吗?我缺少什么?

我可以看到一些重大改进。让我们从头开始,首先我们从不在抽象成员的特征中使用
val
,看

现在让我们看看这里:

object Request {
  def apply[P, R <: Request[P]](code: String)(metadata: String, payload: P): R = code match {
    case "S" => RequestWithString(metadata, payload)
    case "I" => RequestWithInt(metadata, payload)
  }
}

我可以看到一些重大改进。让我们从头开始,首先我们从不在抽象成员的特征中使用
val
,看

现在让我们看看这里:

object Request {
  def apply[P, R <: Request[P]](code: String)(metadata: String, payload: P): R = code match {
    case "S" => RequestWithString(metadata, payload)
    case "I" => RequestWithInt(metadata, payload)
  }
}

将匹配的决策逻辑移动到typeclass:

// this typeclass holds the logic for creating a `Request` for
// a particular payload
sealed abstract class RequestPayloadType[T](val create: (String, T) => Request[T])
object RequestPayloadType {
  implicit object StringPayloadType extends RequestPayloadType[String] (RequestWithString.apply)
  implicit object IntPayloadType extends RequestPayloadType[Int] (RequestWithInt.apply)
}

object Request {
  def apply[P:RequestPayloadType](metadata: String, payload: P): Request[P] = 
    implicitly[RequestPayloadType[P]].create(metadata, payload)
}
scala中的公共模式:将需要特定类型知识的代码移动到具有该知识的编译单元

请记住,拥有单独的请求类,而只拥有一个参数化的类可能会更干净:

case class Request [P:RequestPayloadType](metadata: String, payload: P) {
  // delegate any code that needs to know the type to `implicitly[RequestPayloadType[T]]...`
}

sealed trait RequestPayloadType[T] {
  // specify here code that needs to know the actual type, i.e: 
  // def encode (value: T): String  // abstract 
  // def decode (value: String): T  // abstract
} 
object RequestPayloadType {
  implicit object StringPayloadType extends RequestPayloadType[String] {
    // implement here any `String` specific code, .i.e:
    // def encode (s: String) = s
    // ...
  }
  implicit object IntPayloadType extends RequestPayloadType[Int] {
    // implement here any `Int` specific code, .i.e:
    // def encode (i: Int) = i.toString
    // ...
  }
}

将匹配的决策逻辑移动到typeclass:

// this typeclass holds the logic for creating a `Request` for
// a particular payload
sealed abstract class RequestPayloadType[T](val create: (String, T) => Request[T])
object RequestPayloadType {
  implicit object StringPayloadType extends RequestPayloadType[String] (RequestWithString.apply)
  implicit object IntPayloadType extends RequestPayloadType[Int] (RequestWithInt.apply)
}

object Request {
  def apply[P:RequestPayloadType](metadata: String, payload: P): Request[P] = 
    implicitly[RequestPayloadType[P]].create(metadata, payload)
}
scala中的公共模式:将需要特定类型知识的代码移动到具有该知识的编译单元

请记住,拥有单独的请求类,而只拥有一个参数化的类可能会更干净:

case class Request [P:RequestPayloadType](metadata: String, payload: P) {
  // delegate any code that needs to know the type to `implicitly[RequestPayloadType[T]]...`
}

sealed trait RequestPayloadType[T] {
  // specify here code that needs to know the actual type, i.e: 
  // def encode (value: T): String  // abstract 
  // def decode (value: String): T  // abstract
} 
object RequestPayloadType {
  implicit object StringPayloadType extends RequestPayloadType[String] {
    // implement here any `String` specific code, .i.e:
    // def encode (s: String) = s
    // ...
  }
  implicit object IntPayloadType extends RequestPayloadType[Int] {
    // implement here any `Int` specific code, .i.e:
    // def encode (i: Int) = i.toString
    // ...
  }
}

您对每种类型的请求都做了哪些进一步的处理?@YuvalItzchakov:MongoDB存储与ReactiveMongo,然后从有效负载和远程数据组成一个人类可读的文本,用于将文本发送到远程系统。我需要读/写MongoDB,Request.apply函数的主要用途是在BSONReader[Request]中调用。当前的答案非常有用。但是,我进行了编辑,以便更清楚地说明请求的类型不仅仅取决于有效负载的类型。可能有多个请求子类具有相同类型的负载。您对每种类型的请求都做了哪些进一步的处理?@YuvalItzchakov:MongoDB storage with ReactiveMongo,然后从负载和远程数据组成人类可读的文本,用于将文本发送到远程系统。我需要读/写MongoDB,Request.apply函数的主要用途是在BSONReader[Request]中调用。当前的答案非常有用。但是,我进行了编辑,以便更清楚地说明请求的类型不仅仅取决于有效负载的类型。可能有几个请求子类具有相同类型的负载。我编辑了trait以避免使用VAL,因为这与实际问题无关。谢谢我不明白编码器的用途,为什么我要将有效负载编码/解码到字符串中/从字符串中解码?@K.C.我只是向您展示了一种方法,了解TypeClass以及如何使用它们。关键是你应该在
请求
上定义你想要的任何方法,并使用typeclass方法实现每种类型的方法。我编辑了trait以避免使用VAL,因为这与实际问题无关。谢谢我不明白编码器的用途,为什么我要将有效负载编码/解码到字符串中/从字符串中解码?@K.C.我只是向您展示了一种方法,了解TypeClass以及如何使用它们。关键是您应该在
请求
上定义您想要的任何方法,并使用类型类方法按类型实现它们。