2014-07-14 5 views
3

형식 매개 변수를 사용하는 추상 클래스를 만들고 해당 클래스의 생성자에 다른 동작을 전달해야합니다.제네릭 형식 매개 변수 와일드 카드

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

유형 매개 변수 와일드 카드를 어떻게 표현할 수 있습니까? "?" (자바) 또는 "_"(스칼라) 해킹?

+0

나는 Hack의 전문가는 아니지만, 당신의 설정이'Action'을 monomorphic 클래스에서 상속받는 것과 같다고 말합니다.'ActionBase'는'Action <*>'에 의해 사용 된 인터페이스를 노출시킵니다. 해당 코드를 디자인하는 경우 액션 클래스를 리팩토링 할 수 있습니다. – didierc

답변

0

와일드 카드가 확실하지 않지만 원하는 것을 얻을 수 있습니까? 나는이 HHVM 3.1.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); 

, 내가 얻을 : "오류"를

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'은 type 매개 변수를'Action '으로 생략 했으므로 strict에서는 작동하지 않으며 일반적으로 좋은 생각이 아닙니다. ''행동으로서의 T1''은 타입 검사기에서만 "시행"합니다. 이것은 유형 검사기가 볼 수있는 한만을 의미합니다. HHVM은 현재 제네릭에 대한 소거 의미를 가지고 있으므로 런타임에 적용 할 수 없습니다. 나는 당신의 코드가 최상위에 있다고 생각하거나 hhi 파일을 잊어 버렸기 때문에'DateTime'이'Action '이 아니라는 것을 알 수 없습니다. –

5

해킹

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

는 방법을 정확하게에 따라, 지금 와일드 카드 유형 매개 변수가없는 당신 그러나

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

, 나는 여부 "더미"유형의 위의 위의 질문 : $onSuccess 멤버 변수를 사용하여, 당신은 나중에 결정하는 Action<T>의 일부 특정 서브 클래스로 할 수 있습니다, 그래서 당신이 뭔가를 할 수 있습니다 ar 실제로는 더미인데 - Action<T>의 광대 한 대다수의 사용 사례가 정확히 T이 무엇인지 신경 씁니다. 그렇지 않은 경우 정확히 Action<T>을 사용 하시겠습니까? (전화 사이트에서 T을 걱정하지 않는 경우는 드물지만 희소식이므로이 기능을 실제로 구현하는지 여부를 고려하는 것이 좋습니다.

+0

Github [link] (https://github.com/facebook/hhvm/issues/3183)에서 desugaring에 대한 귀하의 의견에 따라 동작이 완전히 이해됩니다. 그러나 액션 은 비공개로 작동하지 않습니다. 작업 $ onSuccess = null에는 작업에 필요한 첫 번째 유형 인수가 없습니다. 와일드 카드로 우리를 데려옵니다.당신은 맞습니다. 제 경우에는 유형 제약 조건입니다. 'as'는 예를 들어 문제를 해결할 것입니다. 추상 클래스 액션 ... private 액션 $ onSuccess = null. 더 높은 종류의 타입 지원은 추가하기가 쉽지 않다. 나는 형식 검사기 코드를 해킹하고 PR을 제공 할 시간이 있었으면 좋겠습니다. :( – Tino

관련 문제