Scala Universal 与 Existential 类型混淆
Scala Universal vs Existential type confusion
在 this answer 中说...
// Universal types let you write things like:
def combine[T](source: List[T], dest: List[T]): List[T] = {
source ++ dest
}
但是我没看懂解释。
有人可以解释上面的通用类型示例与下面的一些类似示例(包含存在类型)之间的区别吗?
def combine2[_](source: List[_], dest: List[_]): List[_] = {
source ++ dest
}
def combine3(source: List[_], dest: List[_]): List[_] = {
source ++ dest
}
def combine4[A, B](source: List[A], dest: List[B]): List[_] = {
source ++ dest
}
def combine5[T](source: List[T], dest: List[T] forSome {type T}): List[T] forSome {type T} = {
source ++ dest
}
Java 好的措施...
public static List<?> combine6(final List<?> source, final List<?> dest) {
return source;
}
// Why doesn't this compile?
public static <T> List<T> combine7(final List<?> source, final List<?> dest) {
return source;
}
此外,如果我提供类型标签,这是否以任何方式取代了对存在类型的需求?
def combineTypetag[A, B, C](source: List[A], dest: List[B])
(implicit tagA: TypeTag[A], tagB: TypeTag[B], tagC: TypeTag[C]): List[C] = {
source ++ dest
}
combine
表示如果你有两个具有相同元素类型的列表,你会得到相同的类型,例如:
val list1: List[Int] = ...
val list2: List[Int] = ...
val list3 = combine(list1, list2) // also List[Int]
val x = list3.head // Int
val y = x + x // Int
combine
也可以与 不同 类型的列表一起使用,return 最精确的常见类型:
val list1: List[FileInputStream] = ...
val list2: List[ByteArrayInputStream] = ...
val list3 = combine(list1, list2) // List[InputStream]
所有其他选项 return List[T] forSome {type T}
,即一些未知类型的列表(List[_]
只是一种简短的写法):
val list1: List[Int] = ...
val list2: List[Int] = ...
val list4 = combine2(list1, list2) // List[_]
val z = list4.head // Any
val w = z + z // doesn't compile
所以他们只是丢失了类型信息。仅当您不能更精确时才使用存在类型。
Why doesn't this compile?
如果是这样,您希望这里发生什么:
List<?> list = Arrays.asList("a", "b");
List<Integer> list2 = <Integer>combine7(list, list);
?
Also, if I provide typetags, does that in any way replace the need for existential types?
这里不需要存在类型,但是当存在类型存在时,类型标签将无济于事:根据定义,编译器只能在知道静态类型是什么时插入类型标签,因此存在类型不是'不需要。
在 this answer 中说...
// Universal types let you write things like:
def combine[T](source: List[T], dest: List[T]): List[T] = {
source ++ dest
}
但是我没看懂解释。
有人可以解释上面的通用类型示例与下面的一些类似示例(包含存在类型)之间的区别吗?
def combine2[_](source: List[_], dest: List[_]): List[_] = {
source ++ dest
}
def combine3(source: List[_], dest: List[_]): List[_] = {
source ++ dest
}
def combine4[A, B](source: List[A], dest: List[B]): List[_] = {
source ++ dest
}
def combine5[T](source: List[T], dest: List[T] forSome {type T}): List[T] forSome {type T} = {
source ++ dest
}
Java 好的措施...
public static List<?> combine6(final List<?> source, final List<?> dest) {
return source;
}
// Why doesn't this compile?
public static <T> List<T> combine7(final List<?> source, final List<?> dest) {
return source;
}
此外,如果我提供类型标签,这是否以任何方式取代了对存在类型的需求?
def combineTypetag[A, B, C](source: List[A], dest: List[B])
(implicit tagA: TypeTag[A], tagB: TypeTag[B], tagC: TypeTag[C]): List[C] = {
source ++ dest
}
combine
表示如果你有两个具有相同元素类型的列表,你会得到相同的类型,例如:
val list1: List[Int] = ...
val list2: List[Int] = ...
val list3 = combine(list1, list2) // also List[Int]
val x = list3.head // Int
val y = x + x // Int
combine
也可以与 不同 类型的列表一起使用,return 最精确的常见类型:
val list1: List[FileInputStream] = ...
val list2: List[ByteArrayInputStream] = ...
val list3 = combine(list1, list2) // List[InputStream]
所有其他选项 return List[T] forSome {type T}
,即一些未知类型的列表(List[_]
只是一种简短的写法):
val list1: List[Int] = ...
val list2: List[Int] = ...
val list4 = combine2(list1, list2) // List[_]
val z = list4.head // Any
val w = z + z // doesn't compile
所以他们只是丢失了类型信息。仅当您不能更精确时才使用存在类型。
Why doesn't this compile?
如果是这样,您希望这里发生什么:
List<?> list = Arrays.asList("a", "b");
List<Integer> list2 = <Integer>combine7(list, list);
?
Also, if I provide typetags, does that in any way replace the need for existential types?
这里不需要存在类型,但是当存在类型存在时,类型标签将无济于事:根据定义,编译器只能在知道静态类型是什么时插入类型标签,因此存在类型不是'不需要。