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

本文关键字:输入 位置 构造函数 类型参数 | 更新日期: 2023-09-27 18:03:13

在这个回答中,Michael建议将泛型类型参数设为协变,以便允许创建空节点。

我得到泛型类型参数在所有输出位置,因为Tree<T>及其子类型的所有属性都是只读的(val 's)。

但是确实在构造函数的输入位置有类型形参

我认为这段代码在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是不能进一步派生的最子类型。它与Any(或其他语言中最基本的类型)完全相反。

要在c#中模拟这些代码,没有意义:

class Empty : Tree<null> { }

因为这只是非法的c#代码,null似乎也不像Nothing

所以,我必须像这样伪造一个dummy来模仿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中所有可用类型的详尽列表以及它们的描述?因为尽管Basic Types页面列出了大多数常见类型,但它似乎不是一个详尽的列表。没有列出的类型都散布在文档中。就像上面的例子一样,它们只是出现在页面的这里或那里。

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

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

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