我想创建一个抽象类,它接受一个类型参数,该类的构造函数应该传递给另一个Action,例如。
abstract class Action<Tc> {
public function __construct(private ?Action<*> $onSuccess = null) {}
}
如何表达类型参数通配符ie。 “?” Hack中的(Java)或“_”(Scala)?
答案 0 :(得分:4)
Hack目前没有通配符类型参数,因此您可以获得的最接近的实际上是指定一个您实际不需要的虚拟类型参数,例如,
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) {}
// ...
}
但是,我怀疑上面的“虚拟”类型是否真的是假的 - Action<T>
的绝大部分用例都将关注T
究竟是什么,否则你究竟会如何使用Action<T>
? (在极少数情况下,您不关心呼叫站点的T
,但它们很少见,所以我建议您在构建此功能时考虑这是否真的是您的情况。 )
答案 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);
当我针对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类型检查器也返回&#34;没有错误!&#34;。
但是,抽象类的T1 as Action
语句似乎并不强制执行。例如,我可以将实例化行更改为:
$action = new ActionA(new ActionB(new ActionC(new DateTime())));
它很好地哼着,但是typechecker仍然没有返回任何错误。这是在使用<?hh // strict
将类定义输出到他们自己的文件之后。
所以不是你的答案,但也许是关闭?上面的行为可能表明Hack在这种模式中存在一些问题?