【问题标题】:How to write generic function type如何编写泛型函数类型
【发布时间】:2016-08-04 15:12:14
【问题描述】:

我有一个类似这样的界面。

interface Value {
  public function accept<T>(ValueVisitor<T> $visitor): T;
}

由于只有一种方法,我想编写一个类,将闭包转换为Value 的实例。

final class ClosureValue implements Value {
  public function __construct(
    private (function<T>(ValueVisitor<T>): T) $f
  ) {}

  public function accept<T>(ValueVisitor<T> $visitor): T {
    $f = $this->f;
    return $f($visitor);
  }
}

但是,function&lt;T&gt;(ValueVisitor&lt;T&gt;): T 类型中的 &lt;T&gt; 是语法错误。不管我把&lt;T&gt;放在哪里,它都不会解析。

如何在 Hack 中编写这个?

【问题讨论】:

  • 请原谅我缺乏想象力,但是您的通用闭包 $f 甚至可以做什么,因为它无法从其环境中捕获 T 类型的值?它如何与ValueVisitor&lt;T&gt; 有效交互?
  • ValueVisitor&lt;T&gt; 具有返回 Ts 的方法,因此函数 (function &lt;T&gt;(ValueVisitor&lt;T&gt;) :T) 必须返回 T 并且它必须这样做的唯一方法是调用 ValueVisitor&lt;T&gt; 的方法给它。
  • 我很好奇您打算在ValueVisitor 上进行多少种不同的方法调用组合,但总的来说这似乎是合理的。您最好的选择可能是向 Hack 团队提出功能请求。 (就我个人而言,我也希望最终实现匿名类,这也可以帮助你)
  • 是的,这是匿名泛型函数github.com/facebook/hhvm/issues/7451 和匿名类github.com/facebook/hhvm/issues/6039 的问题。

标签: generics anonymous-function hacklang


【解决方案1】:

现在我不能尝试,如果它可以工作,但这可能有效:

final class ClosureValue<T> implements Value {
    public function __construct(
        private (function(ValueVisitor<T>) : T) $myF
    ) {

    }


    public function accept(ValueVisitor<T> $visitor) : T {
        $fn = $this->myF;
        return $fn($visitor);
    } 
}

【讨论】:

  • ClosureValue 将成为一个只能接受产生T 类型值的访问者的值(由构造决定),并且accept 方法不再是通用的,因此与@ 不兼容Value的987654325@方法。
【解决方案2】:

它对我来说很好......

classes.hh

<?hh // strict

class ValueVisitor<T>
{
    protected T $value;
    public function __construct(T $new) { $this->value = $new; }
    public function get(): T { return $this->value; }
}

interface Value { public function accept<T>(ValueVisitor<T> $visitor): T; }

final class ClosureValue<T> implements Value {
    public function __construct(
    private (function(ValueVisitor<T>) : T) $myF
) {

}

public function accept(ValueVisitor<T> $visitor) : T {
    $fn = $this->myF;
    return $fn($visitor);
}

// main.hh

<?hh // strict

class MyClass
{
    public function __construct(
        protected string $myVal
    ) { }

    public function getMyVal(): string { return $this->myVal; }
}

function main<T>() : void
{
    $visitor = new ValueVisitor(12);
    $val = new ClosureValue(function(ValueVisitor<int> $f): int {
        return $f->get();
    });

    echo $val->accept($visitor);


    $visitor2 = new ValueVisitor('Foo');
    $val2 = new ClosureValue(function(ValueVisitor<string> $f): string {
        return $f->get();
    });

    echo $val2->accept($visitor2);

    $visitor3 = new ValueVisitor(new MyClass("asd"));
    $val3 = new ClosureValue(function(ValueVisitor<MyClass> $f): MyClass {
        return $f->get();
    });

    print_r($val3->accept($visitor2));
}

index.hh

<?hh // partial    

require 'classes.hh';
require 'helpers.hh';
require 'main.hh';

main();

【讨论】:

  • 这不是访问者的工作方式。 ValueVisitor&lt;T&gt; 并不表示访问者获取类型为 T 的值,而是表示访问者生成类型为 T 的值。被访问的值的类型是ValueVisitor 方法的参数,而不是T。您可以在此处了解访问者模式:en.wikipedia.org/wiki/Visitor_pattern
  • 您因语法错误而寻求帮助,所以我的回答仅用于解决您的语法错误。然而它解决了......
  • 用无效的代码替换语法错误并没有帮助。
猜你喜欢
  • 2014-10-08
  • 1970-01-01
  • 2022-01-10
  • 2016-03-21
  • 2016-10-04
  • 1970-01-01
  • 2019-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多