Scala 部分应用类型参数和类型标记的难写方法
在下面的示例中,我正在寻找从调用Scala 部分应用类型参数和类型标记的难写方法,scala,type-parameter,partially-applied-type,Scala,Type Parameter,Partially Applied Type,在下面的示例中,我正在寻找从调用apply中删除类型参数S的方法: object Attribute { trait Int [S] extends Attribute[S] trait Boolean[S] extends Attribute[S] // etc. } sealed trait Attribute[S] trait Attributes[S] { protected def get(key: String): Option[Attribute[S]]
apply
中删除类型参数S
的方法:
object Attribute {
trait Int [S] extends Attribute[S]
trait Boolean[S] extends Attribute[S] // etc.
}
sealed trait Attribute[S]
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A <: Attribute[S]](key: String)
(implicit tag: reflect.ClassTag[A]): Option[A] =
get(key) match {
case Some(attr: A) => Some(attr)
case _ => None
}
}
我试图做的是修改apply
definition,以允许以下内容:
trait Test2[S] {
def map: Attributes[S]
map[Attribute.Int]("foo") // use partially applied attribute type
}
编辑:那么继马吕斯的建议和评论之后,为什么下面的内容仍然会产生擦除警告:
import reflect.runtime.universe._
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A[x] <: Attribute[x]](key: String)
(implicit tag: TypeTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr: A[S]) => Some(attr)
case _ => None
}
}
import reflect.runtime.universe_
特质属性{
受保护的def get(键:字符串):选项[属性]
def应用[A[x]一些(属性)
案例=>无
}
}
对我来说,这显然没有什么意义。一方面,我有A[S]
的完整类型标记可用。另一方面,它甚至应该在没有它的情况下完全工作,因为Attribute
在S
中是不变的,所以如果我得到一个选项[Attribute[S]
,并且我匹配一些(attr:A[x])
,唯一的可能性是x==S
编辑2:解决方案的条件是
属性
特征的形状不变,例如,不将类型构造函数参数S
移动到成员字段。我认为您需要更高类型的类型。我这样重写了您的代码:
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr: A[S]) => Some(attr)
case _ => None
}
}
trait属性[S]{
受保护的def get(键:字符串):选项[属性]
def apply[A[uu]Some(属性)
案例=>无
}
}
请注意,A
type参数现在是一个高阶类型。因此,在apply
方法中的每次出现时,您都需要将A
应用到另一个类型,以获得正确的类型
此问题为更高阶类型提供了更多信息:
我认为您需要更高级的类型。我将您的代码改写为:
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr: A[S]) => Some(attr)
case _ => None
}
}
trait属性[S]{
受保护的def get(键:字符串):选项[属性]
def apply[A[uu]Some(属性)
案例=>无
}
}
请注意,A
type参数现在是一个高阶类型。因此,在apply
方法中的每次出现时,您都需要将A
应用到另一个类型,以获得正确的类型
此问题为更高阶类型提供了更多信息:
您是否考虑过利用隐式
类标记的未应用
?如果我正确理解文档,如果attr
与其类型不完全匹配,则标记中的未应用
将返回一个None。如果匹配,它将返回某种类型的a[S]
。因此经过重构以不适用地使用,您的代码如下所示:
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr) => tag.unapply(attr)
case _ => None
}
def apply[一个[]tag.unapply(属性)
案例=>无
}
您是否考虑过利用隐式类标签的未应用
?如果我正确理解文档,如果属性
与其类型不完全匹配,则标签中的未应用
将返回一个无。如果匹配,它将返回一个部分类型a[S]
。因此经过重构以不适用地使用,您的代码如下所示:
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr) => tag.unapply(attr)
case _ => None
}
def apply[一个[]tag.unapply(属性)
案例=>无
}
单向。请注意,要将任何类型称为Int,甚至是嵌套类型,都需要一定的胆量
import scala.reflect._
sealed trait Attribute {
type S
}
object Attribute {
trait Ints extends Attribute { type S = Int }
}
/** A container for attributes of a certain type.
*/
trait Attributes[E] {
type Attr = Attribute { type S <: E }
protected def get(key: String): Option[Attr]
/** Retrieve the value for the given key.
* @tparam A must be our notion of Attribute
* @return optionally the A you asked for
*/
def apply[A <: Attr](key: String)(implicit tag: ClassTag[A]): Option[A] =
get(key) match {
case Some(attr: A) => Some(attr)
case _ => None
}
}
trait Test2 {
/** Map keys to ints. */
def map: Attributes[Int]
/** Retrieve a value. */
map[Attribute.Ints]("foo") // use partially applied attribute type
}
导入scala.reflect_
封闭性状属性{
S型
}
对象属性{
trait Int扩展属性{type S=Int}
}
/**特定类型属性的容器。
*/
特质属性[E]{
类型Attr=属性{type S None
}
}
性状测试2{
/**将键映射到int*/
def映射:属性[Int]
/**检索一个值*/
map[Attribute.Ints](“foo”)//使用部分应用的属性类型
}
单向。请注意,要将任何类型称为Int,甚至是嵌套类型,都需要一定的胆量
import scala.reflect._
sealed trait Attribute {
type S
}
object Attribute {
trait Ints extends Attribute { type S = Int }
}
/** A container for attributes of a certain type.
*/
trait Attributes[E] {
type Attr = Attribute { type S <: E }
protected def get(key: String): Option[Attr]
/** Retrieve the value for the given key.
* @tparam A must be our notion of Attribute
* @return optionally the A you asked for
*/
def apply[A <: Attr](key: String)(implicit tag: ClassTag[A]): Option[A] =
get(key) match {
case Some(attr: A) => Some(attr)
case _ => None
}
}
trait Test2 {
/** Map keys to ints. */
def map: Attributes[Int]
/** Retrieve a value. */
map[Attribute.Ints]("foo") // use partially applied attribute type
}
导入scala.reflect_
封闭性状属性{
S型
}
对象属性{
trait Int扩展属性{type S=Int}
}
/**特定类型属性的容器。
*/
特质属性[E]{
类型Attr=属性{type S None
}
}
性状测试2{
/**将键映射到int*/
def映射:属性[Int]
/**检索一个值*/
map[Attribute.Ints](“foo”)//使用部分应用的属性类型
}
这只是为了表明@cmbaxter的答案与预期一样有效。我也将重述初始代码,以使其完全可执行:
//属性接口
object Attribute {
trait Int [S] extends Attribute[S]
trait Boolean[S] extends Attribute[S] // etc.
}
sealed trait Attribute[S]
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr) => tag.unapply(attr)
case _ => None
}
}
}
class Test {
val map = new Attributes[Foo] {
def get(key: String) = key match {
case "foo" => Some(new Attribute.Int [Foo] { override def toString = "I" })
case "bar" => Some(new Attribute.Boolean[Foo] { override def toString = "B" })
case _ => None
}
}
println(s"An int attr named `foo`: ${map[Attribute.Int ]("foo")}")
println(s"A bool attr named `foo`: ${map[Attribute.Boolean]("foo")}")
println(s"An int attr named `bar`: ${map[Attribute.Int ]("bar")}")
println(s"A bool attr named `bar`: ${map[Attribute.Boolean]("bar")}")
println(s"An int attr named `???`: ${map[Attribute.Int ]("???")}")
println(s"A bool attr named `???`: ${map[Attribute.Boolean]("???")}")
}
//属性映射界面
object Attribute {
trait Int [S] extends Attribute[S]
trait Boolean[S] extends Attribute[S] // etc.
}
sealed trait Attribute[S]
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr) => tag.unapply(attr)
case _ => None
}
}
}
class Test {
val map = new Attributes[Foo] {
def get(key: String) = key match {
case "foo" => Some(new Attribute.Int [Foo] { override def toString = "I" })
case "bar" => Some(new Attribute.Boolean[Foo] { override def toString = "B" })
case _ => None
}
}
println(s"An int attr named `foo`: ${map[Attribute.Int ]("foo")}")
println(s"A bool attr named `foo`: ${map[Attribute.Boolean]("foo")}")
println(s"An int attr named `bar`: ${map[Attribute.Int ]("bar")}")
println(s"A bool attr named `bar`: ${map[Attribute.Boolean]("bar")}")
println(s"An int attr named `???`: ${map[Attribute.Int ]("???")}")
println(s"A bool attr named `???`: ${map[Attribute.Boolean]("???")}")
}
//跑步
new Test
An int attr named `foo`: Some(I)
A bool attr named `foo`: None
An int attr named `bar`: None
A bool attr named `bar`: Some(B)
An int attr named `???`: None
A bool attr named `???`: None
这只是为了表明@cmbaxter的答案与预期的一样有效。我还将重述初始代码,以使其完全可执行:
//属性接口
object Attribute {
trait Int [S] extends Attribute[S]
trait Boolean[S] extends Attribute[S] // etc.
}
sealed trait Attribute[S]
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr) => tag.unapply(attr)
case _ => None
}
}
}
class Test {
val map = new Attributes[Foo] {
def get(key: String) = key match {
case "foo" => Some(new Attribute.Int [Foo] { override def toString = "I" })
case "bar" => Some(new Attribute.Boolean[Foo] { override def toString = "B" })
case _ => None
}
}
println(s"An int attr named `foo`: ${map[Attribute.Int ]("foo")}")
println(s"A bool attr named `foo`: ${map[Attribute.Boolean]("foo")}")
println(s"An int attr named `bar`: ${map[Attribute.Int ]("bar")}")
println(s"A bool attr named `bar`: ${map[Attribute.Boolean]("bar")}")
println(s"An int attr named `???`: ${map[Attribute.Int ]("???")}")
println(s"A bool attr named `???`: ${map[Attribute.Boolean]("???")}")
}
//属性映射界面
object Attribute {
trait Int [S] extends Attribute[S]
trait Boolean[S] extends Attribute[S] // etc.
}
sealed trait Attribute[S]
trait Attributes[S] {
protected def get(key: String): Option[Attribute[S]]
def apply[A[_] <: Attribute[_]](key: String)
(implicit tag: reflect.ClassTag[A[S]]): Option[A[S]] =
get(key) match {
case Some(attr) => tag.unapply(attr)
case _ => None
}
}
}
class Test {
val map = new Attributes[Foo] {
def get(key: String) = key match {
case "foo" => Some(new Attribute.Int [Foo] { override def toString = "I" })
case "bar" => Some(new Attribute.Boolean[Foo] { override def toString = "B" })
case _ => None
}
}
println(s"An int attr named `foo`: ${map[Attribute.Int ]("foo")}")
println(s"A bool attr named `foo`: ${map[Attribute.Boolean]("foo")}")
println(s"An int attr named `bar`: ${map[Attribute.Int ]("bar")}")
println(s"A bool attr named `bar`: ${map[Attribute.Boolean]("bar")}")
println(s"An int attr named `???`: ${map[Attribute.Int ]("???")}")
println(s"A bool attr named `???`: ${map[Attribute.Boolean]("???")}")
}
//跑步
new Test
An int attr named `foo`: Some(I)
A bool attr named `foo`: None
An int attr named `bar`: None
A bool attr named `bar`: Some(B)
An int attr named `???`: None
A bool attr named `???`: None
这个版本的问题是,类标记没有在这里生效:警告:抽象类型模式A[S]未被选中,因为它被擦除消除了。
。是的,这很奇怪。如果我添加了println(标记)
在apply
方法中,它打印了正确的类型名,所以我不知道是怎么回事。也许它应该提升到它自己的so问题。使用TypeTag
ClassTags
只捕获被擦除的类型。@gzm0是的,我尝试过了。但是,关于擦除的警告没有发出。这个版本的问题是ClassTag在这里不起作用:警告:抽象类型模式A[S]未被选中,因为它被擦除消除了。
。是的,这很奇怪。如果我添加println(标记)
在apply
方法中,它打印了正确的类型名,所以我不知道是怎么回事。也许它应该提升到它自己的so问题。使用TypeTag
ClassTags
只捕获被擦除的类型。@gzm0是的,我尝试过了。但是关于擦除的警告不会消失。移动s