scala – 类型变量的类型模式的用例和示例
|
我发现阅读规范
scala支持绑定类型变量做一个类型模式匹配:
Map(1 -> "one",2 -> "two") match {
case l: Map[k,v] =>
// binds k to Int and v to String
// k and v are types as shown here:
val i: Iterator[Tuple2[k,v]] = l.iterator
println(i.mkString(","))
}
有没有什么花哨的事情或实际的事情我可以做到这一点?或绑定类型变量仅对类型文档目的有用吗? 对我来说,Scala有时候需要类型注释,例如定义函数,所以我试过: def prepender(obj: Any) = obj match {
case xs: List[a] => (x: a) => x :: xs
case opt: Some[a] => (x: a) => x :: Nil
}
但是返回函数的类型是奇怪的: prepender: (obj: Any)a with a => List[Any] forSome { type a; type a }
scala> val p = prepender(List(1,2))
p: a with a => List[Any] forSome { type a; type a } = <function1>
scala> p(1)
<console>:10: error: type mismatch;
found : Int(1)
required: a(in value res7) with (some other)a(in value res7) where
type (some other)a(in value res7),type a(in value res7)
解决方法
我希望这不会太长,但是我真的很怀疑,这就是为什么我会先尝试提供一个快速的答案:“当你命名(抽象)某些东西时,主要的用例是在以后提及”.那现在没有帮助,是吗?
考虑这个简单的Scala功能: val sum = (a: Int,b: Int) => a + b 编译器不需要知道a是a,b是b.所有它需要知道一个以及b是类型Int和一个来到b之前(在这种情况下,这是没有关系的,因为添加是可交换的,但编译器关心!). Scala提供了一个(不要误会我也喜欢它)编译器友好的占位符语法,作为这个“假设”的证明. val sum: (Int,Int) => Int = _ + _ // where the 1st _ differs from the 2nd _ 现在看看这个: case x: SomeTypeParameterizedWith[AnotherType] // AnotherType is erased anyway case x: SomeParameterizedType[_] // Existential type case x: SomeParameterizedType[kind] // Existential type which you can reference 当您不关心类型参数时,请使用占位符语法.当你做(无论什么原因)时,请注意你应该用小写命名为type参数,以便编译器知道你想把它当作一个标识符. 回到你的问题 存在类型的主要用途是围绕Java的通配符类型. // This is a Java class with wildcards
public class Wild {
public java.util.Collection<?> contents() {
java.util.Collection<String> stuff = new Vector<String>();
stuff.add("a");
stuff.add("b");
stuff.add("see");
return stuff;
}
}
// This is the problem
import scala.collection.mutable.Set
val iter = (new Wild).contents.iterator
val set = Set.empty[???] // what type goes here?
while (iter.hasMore)
set += iter.next()
// This is the solution
def javaSet2ScalaSet[T](jset: java.util.Collection[T]): Set[T] = {
val sset = Set.empty[T] // now T can be named!
val iter = jset.iterator
while (iter.hasNext)
sset += iter.next()
sset
}
好的,那刚才发生了什么?简单的泛型,没有魔法吗?如果您是日常处理仿制药,这对您来说看起来是正常的,但您忘记了将范围引入范围的超级概念仅适用于类和方法.如果你在一个班级或一个方法之外,只是在无处不在的随机范围(如REPL)怎么办?或者如果你在一个类或一个方法,但是类型参数还没有被引入其范围呢?这是你的问题和这个答案来的地方. val set = new Wild().contents match {
case jset: java.util.Collection[kind] => {
val sset = Set.empty[kind]
val iter = jset.iterator
while (iter.hasNext)
sset += iter.next()
sset
}
}
标识符类型是必需的,因此编译器可以验证您是指同一件事. 注意,您不能只是将字符串添加到集合中,因为集合的类型为Set [_]. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
