在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問題只是無關緊要(它要求建議一些外部資源) 。 –