简体   繁体   English

Scala通用vs存在类型混淆

[英]Scala Universal vs Existential type confusion

In this answer it says... 这个答案中说...

  // Universal types let you write things like:

  def combine[T](source: List[T], dest: List[T]): List[T] = {
    source ++ dest
  }

But I did not understand the explanation. 但是我不明白这个解释。

Can someone explain the difference between the universal type example above and some of the similar examples (which contain existential types) below? 有人可以解释上面的通用类型示例与下面的一些类似示例(包含存在类型)之间的区别吗?

  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 for good measure... 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;
}

Also, if I provide typetags, does that in any way replace the need for existential types? 另外,如果我提供了类型标签,那么这是否可以代替对现有类型的需要?

  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 says that if you have two lists with the same element type, you get the same type back, eg: 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 can also be used with lists of different types, and return the most precise common type: combine还可以用于不同类型的列表,并返回最精确的常见类型:

val list1: List[FileInputStream] = ...
val list2: List[ByteArrayInputStream] = ...
val list3 = combine(list1, list2) // List[InputStream]

All the other options return List[T] forSome {type T} , ie list of some unknown type ( List[_] is just a short way to write this): 所有其他选项返回List[T] forSome {type T} ,即某种未知类型的List[_]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

So they simply lose the type information. 因此,它们只会丢失类型信息。 Only use existential types when you can't be any more precise. 仅当无法精确使用时,才使用存在类型。

Why doesn't this compile? 为什么不编译?

If it did, what would you expect to happen here: 如果确实如此,您期望在这里发生什么:

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? 另外,如果我提供了类型标签,那么这是否可以代替对现有类型的需要?

There is no need for existential types here, but when there is, type tags won't help: the compiler by definition can only insert type tags when it knows what the static types are, so that existential types aren't needed. 这里不需要存在类型,但是如果存在,类型标签将无济于事:根据定义,编译器只能在知道静态类型是什么时才插入类型标签,因此不需要存在类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM