一个协变类型参数可以在构造函数的输入位置吗?

在这个答案中 , Michael建议将泛型类型参数作为协变量,以允许创建一个空节点。

由于Tree<T>及其子类型的所有属性都是只读的( val ),因此泛型类型参数位于所有输出位置。

但是它在构造函数的输入位置中具有类型参数。

我认为这个代码在C#中不起作用,所以我尝试了一下,而且我感到惊讶,它工作得很好。

 // See this: https://stackoverflow.com/questions/36753579/algebraic-data-types-in-kotlin // Short url: https://stackoverflow.com/a/36753782/303685 interface ITree<out T> { } class Tree<T>: ITree<T> { } sealed class Node<T> : Tree<T> { private readonly T _left; private readonly T _right; public Node(T left, T right) { _left = left; _right = right; } public T Left { get { return _left; } } public T Right { get { return _right; } } } class Program { static void CovarianceTest1() { ITree<object> tree = new Node<string>("Hello", "World!"); } } 

我现在意识到,在这个练习中,我学到了一些新的差异。

所以,我的第一个问题是:

在构造函数的输入位置是否允许协变类型参数? 在其他地方是什么类型的参数可以忽略他们的差异限定符?

我了解到的另一件事是变体泛型类型参数可能不会出现在变体接口声明中,如下面的示例所示。

 interface ITree<out T> { } 

您会看到ITree<out T>接口在输入或输出位置都没有T 这也对我感到震惊。

我的第二个问题是:

另一个问题是,Kotlin中的Nothing类型的C#等价物是Nothing 答案是Nothing是最不能进一步派生的子类型。 它与Any (或其他语言中最基本的类型)完全相反。

要在C#中模拟该代码,没有任何意义:

 class Empty : Tree<null> { } 

因为这只是非法的C#代码, null也不类似Nothing

所以,我不得不伪造一个虚拟样子来模仿Empty类声明。

 sealed class Dummy { } sealed class Empty : Tree<Dummy> { private static Empty _empty = null; private static object syncLock = new object(); private Empty() { } public Empty Instance { get { if (_empty == null) { lock (syncLock) { if (_empty == null) { _empty = new Empty(); } } } return _empty; } } } 

我的第三个和最后一个问题是:

因此,我的最后一个问题是,是否有一个地方包含了Kotlin中所有可用类型的详尽清单及其描述? 因为即使“ 基本类型”页面列出了大多数常见的页面 ,但它似乎不是一个详尽的列表。 这里没有列出的类型全部洒在文档上 。 就像上面的例子一样,它们只是在这里或那里的页面上出现。

Kotlin附带的所有类型都在其API参考中进行了描述,特别是kotlin软件包:

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/