2014-07-14 130 views
3

我想創建一個抽象類,它接受一個類型參數,並且該類的構造函數應該傳遞另一個動作,例如。泛型類型參數通配符

abstract class Action<Tc> { 
    public function __construct(private ?Action<*> $onSuccess = null) {} 
} 

我該如何表達一個類型參數通配符ie。 「?」 (Java)或「_」(Scala)在Hack?

+0

我並不是Hack方面的專家,但在我看來,你的設置相當於讓'Action'從一個單形類繼承,比如說'ActionBase',它暴露了所有'Action <*>'使用的接口。如果你正在設計代碼,你可以用這種方式重構你的動作類。 – didierc

回答

0

不確定通配符,但可以實現你想要的嗎?

<?hh 
    abstract class Action<T1 as Action, T2> { 
     public function __construct(private ?T1 $onSuccess = null, private ?T2 $bla = null) {} 
    } 

    class ActionA<T1 as Action, T2> extends Action<T1, T2> {} 
    class ActionB<T1 as Action, T2> extends Action<T1, T2> {} 
    class ActionC<T1 as Action, T2> extends Action<T1, T2> {} 

    $action = new ActionA(new ActionB(new ActionC(null))); 

    var_dump($action); 

當我跑這對HHVM 3.1.0,我得到: 「沒有錯誤」

object(ActionA)#1 (2) { 
    ["onSuccess":"Action":private]=> 
    object(ActionB)#2 (2) { 
    ["onSuccess":"Action":private]=> 
    object(ActionC)#3 (2) { 
     ["onSuccess":"Action":private]=> 
     NULL 
     ["bla":"Action":private]=> 
     NULL 
    } 
    ["bla":"Action":private]=> 
    NULL 
    } 
    ["bla":"Action":private]=> 
    NULL 
} 

而且3.1.0類型檢查也返回。

但是,關於抽象類的T1 as Action聲明似乎沒有強制執行。舉例來說,我可以改變的實例行:

$action = new ActionA(new ActionB(new ActionC(new DateTime()))); 

它沿着細哼唱,與typechecker返回沒有錯誤依然。這是在將類定義帶入<?hh // strict的文件之後。

所以不是你的答案,但也許關閉?上面的行爲可能表明Hack有這種模式的一些問題?

+1

'T1 as Action'省略了'Action '的類型參數,所以不會嚴格工作,一般不是一個好主意。 'T1 as Action'只在類型檢查器中「強制執行」,這意味着只有類型檢測器可以看到 - HHVM現在對泛型進行擦除語義,所以不能在運行時強制執行。我懷疑你的代碼處於頂層,或者你忘記了hhi文件,所以我們看不到'DateTime'不是'Action '。 –

5

哈克沒有通配符類型的參數,現在,所以最接近你可以得到實際上是指定你實際上並不需要一個虛擬的類型參數,例如,

abstract class Action<Tc, Ta> { 
    public function __construct(private ?Action<Ta> $onSuccess = null) {} 
    // ... 
} 

根據如何正是你使用$onSuccess成員變量,你可能希望它是Action<T>一些具體子類稍後確定,所以你可能想是這樣的:

abstract class Action<Tc, Ta, To as Action<Ta>> { 
    public function __construct(private ?To $onSuccess = null) {} 
    // ... 
} 

然而,我懷疑是否上面的「虛擬」類型以上AR e真的是一個虛擬 - Action<T>的絕大多數用例都會關心T究竟是什麼,否則您將如何使用Action<T>? (當然在極少數情況下,您並不關心呼叫站點上的T,但它們很罕見,所以我鼓勵您在構建此功能時考慮是否確實是您的情況。)

+0

考慮到你對Github上的desugaring的評論,[[link](https://github.com/facebook/hhvm/issues/3183)),這種行爲總是有意義的。然而,Action 將不能用作私人行動 $ onSuccess = null缺少Action所需的第一個類型參數。這使我們回到通配符。你是對的,在我的情況下,類型約束即。 'as'將解決問題,例如。抽象類Action ... private Action $ onSuccess = null。我想更高的親屬類型支持是不平凡的增加。我希望我有時間在類型檢查代碼中進行攻擊並提供一個PR ...... :( – Tino