协变类型参数可以在构造函数的输入位置吗?
问题描述:
在this answer,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
。这也对我感到震惊。
我的第二个问题是:
而其他的问题我已经是,什么是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;
}
}
}
我的第三个,也是最后的问题是:
因此,我的最后一个问题是,是否有一个包含所有类型的科特林提供一个详尽的清单及其说明的地方吗?因为即使Basic Types page列出了大多数常见的,它似乎不是一个详尽的列表。这里没有列出的类型全部喷洒在the documentation之上。就像上面的例子一样,它们只是在这里或那里的页面上出现。
你的问题的方式过于宽泛,合并了许多不同的主题。首先,关于构造函数,类不是变体,接口是。而构造函数不是接口的一部分。不管你喜欢什么,你都可以违背班级本身的变化。这并不重要,因为只有通过界面处理类型时,才能使用差异。 –
@PeterDuniho谢谢。你是否建议我将问题分解并作为多个问题发布? –
是的,我认为那会更好。虽然,我预测你的#2问题的答案是“你不能这样做”(因为你不能),而你的#3问题只是无关紧要(它要求建议一些外部资源) 。 –