协变类型参数可以位于构造函数的输入位置吗?
本文关键字:输入 位置 构造函数 类型参数 | 更新日期: 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
包: