hack形状介绍

2018-11-01 17:33 更新

一个形状的一组由零个或多个数据字段放在一起作为一个整体;它是一个数组的键是由Hack typechecker跟踪。

例如:

<?hh 
shape ('x'  =>  int , 'y'  =>  int )

形状的定义包含一组有序的字段,每个字段都有一个名称和一个类型。在上述情况下,形状由两个int字段组成,分别是名称'x'和名称'y'。

<?hh

namespace Hack\UserDocumentation\Shapes\Introduction\Examples\Intro;

type Point = shape('x' => int, 'y' => int);

class C1 {
  private Point $origin;
  private function __construct(int $x = 0, int $y = 0) {
    $this->origin = shape('x' => $x, 'y' => $y);
  }
}

function distance_between_2_Points(Point $p1, Point $p2): float {
  // access shape info via keys in the shape map, in this case `x` and `y`
  $dx = $p1['x'] - $p2['x'];
  $dy = $p1['y'] - $p2['y'];
  return sqrt($dx*$dx + $dy*$dy);
}

function run(): void {
  $p1 = shape('x' => 4, 'y' => 6);
  $p2 = shape('x' => 9, 'y' => 2);
  var_dump(distance_between_2_Points($p1, $p2));
}

run();

Output

float(6.4031242374328)

虽然我们可以直接使用形状类型,但是通常创建别名(例如Point上面的名称)是方便的,而是使用它。

访问字段

使用其名称作为在对应形状类型的形状上操作的下标表达式中的键来访问形状中的字段。例如:

字段的名称可以用两种可能的形式之一写成:

  • 单引号(如上例所示)
  • 类型string或类的常数int

请注意,整数文字不能直接用作字段名称。

给定形状定义中的所有字段的名称必须是不同的,并且具有相同的形式。

所有非可变字段都是必需的

例如,当从函数返回形状时,必须考虑所有字段; 否则Hack typechecker会引发错误。

<?hh

namespace Hack\UserDocumentation\Shapes\Introduction\Examples\Fields;

type user = shape('id' => int, 'name' => string);

class UserClass {
  public static function create_user(int $id, string $name): user {
    $user = shape();
    $user['id'] = $id;
    return $user;
  }
}

function run(): void {
  var_dump(UserClass::create_user(1, 'James'));
}

run();

Output

array(1) {
  ["id"]=>
  int(1)
}

在上面的例子中,我们忘记设置该形状的名称字段。请注意,HHVM仍将运行代码,因为它只是覆盖在下面的数组。

可空字段是可选的

typechecker将可选项和可空值混合。shape('name' => ?string)将同时匹配shape('name' => null)和shape()。因此,如果省略一个可空的字段,那么typechecker就不会引起错误。但是,OutOfBoundsException如果您尝试读取省略的字段,则运行时将会引发。

类常数(Class Constants

类常数可用于Shapes。

<?hh

namespace Hack\UserDocumentation\Shapes\Introduction\Examples\ClassConstants;

class C2 {
  const string KEYA = 'x';
  const string KEYB = 'y';
  const int KEYX = 10;
  const int KEYY = 23;
}

type PointS = shape(C2::KEYA => int, C2::KEYB => int);
type PointI = shape(C2::KEYX => int, C2::KEYY => int);

function print_pointS(PointS $p): void {
  var_dump($p);
}

function print_pointI(PointI $p): void {
  var_dump($p);
}

function run(): void {
  print_pointI(shape(C2::KEYX => -1, C2::KEYY => 2));
  print_pointS(shape(C2::KEYA => -1, C2::KEYB => 2));
}

run();

Output

array(2) {
  [10]=>
  int(-1)
  [23]=>
  int(2)
}
array(2) {
  ["x"]=>
  int(-1)
  ["y"]=>
  int(2)
}

在上面我们例子中的整数类常量的情况下,通过任意选择,x坐标被存储在具有键10的元素中,而y坐标被存储在具有键23的元素中。

没有类型别名的形状

形状不必具有与其相关联的类型别名。这是一个在所有地方使用文字形状语法的例子。

<?hh

namespace Hack\UserDocumentation\Shapes\Intro\Examples\Anonymous;

class C {

  public function __construct(
    private shape('real' => float, 'imag' => float) $prop) {}

  public function setProp(shape('real' => float, 'imag' => float) $val): void {
    $this->prop = shape('real' => $val['real'], 'imag' => $val['imag']);
  }

  public function getProp(): shape('real' => float, 'imag' => float) {
    return $this->prop;
  }
}

function main(): void {
  $c = new C(shape('real' => -2.5, 'imag' => 1.3));
  var_dump($c);
  $c->setProp(shape('real' => 2.0, 'imag' => 99.3));
  var_dump($c->getProp());
}

main();

Output

object(Hack\UserDocumentation\Shapes\Intro\Examples\Anonymous\C)#1 (1) {
  ["prop":"Hack\UserDocumentation\Shapes\Intro\Examples\Anonymous\C":private]=>
  array(2) {
    ["real"]=>
    float(-2.5)
    ["imag"]=>
    float(1.3)
  }
}
array(2) {
  ["real"]=>
  float(2)
  ["imag"]=>
  float(99.3)
}

注意事项

形状是数组; 即呼叫is_array()将返回true。但是,您可以使用不能使用形状的数组执行一些操作。

  • 您不能用未知键读取或写入。例如,$shape[$var]无效。键必须是字符串字面值或类常量。
  • 您不能[]在形状上使用数组追加运算符。
  • 你不能foreach 形状,因为它不实现TraversableContainer


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号