1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

HHVM/Hack 型システム その1

Posted at

型システムを制するものはHackを制す

Hack and HHVM Advent Calendar 2018も中盤になってきましたので、
Hackの型システムに慣れるために、色々みていきます
紹介するものは全てstrict前提です。

プリミティブ

公式ドキュメントにもありますが、まずは基本の型からです。
PHPとは微妙に異なります。

bool

boolは当然boolのみとなります。

<?hh // strict

namespace Acme\Hacklang;

class TypeSystem {

  public function is(): bool {
    return true;
  }

  public function is_is(bool $bool): bool {
    return $bool;
  }
}

int / float

intとfloatを混ぜて使うことはできません。
下記は共にTypeErrorです。

  public function is(): int {
    return 1.0;
  }

  public function is_is(float $bool = 0.1): int {
    return $bool;
  }

string

文字列も当然それ以外は利用できません。

array

これまでも紹介してきた様にarrayはPHPと同様にarrayだけでは不十分となります。

文字列のarrayを宣言しておいてintとなるとErrorとなります。
下記のは全てTypeErrorです。

  public function failedStringVarray(): varray<string> {
    return [1];
  }

  public function failedStringStringDarray(): darray<string, string> {
    return ['hello' => 1];
  }

  public function failedStringArray(): array<string> {
    return [1];
  }

  public function failedStringStringArray(): array<string, string> {
    return ['hello' => 1];
  }

  public function failedNestedMixedArray(): array<mixed> {
    return [
      1,
      'testing',
      'hello' => 1234,
      'nested' => [
        1 => 2,
        'testing',
        'hello' => 1234,
      ]
    ];
  }

  public function failedMixedArray(): array<mixed, mixed> {
    return [
      1,
      'testing',
      'hello' => 1234,
      'nested' => [
        1 => 2,
        'testing',
        'hello' => 1234,
      ]
    ];
  }

resource

PHPと同じです。

  public function is(): resource {
    return \fopen("ftp://user:password@example.com/somefile.txt", "w");;
  }

プリミティブ型以外で利用するものです。

void

戻りがないことの宣言です。
ユニットテストの場合は基本的にvoidになるので、記述しなければいけません。

混合系

普通のものから特殊なものまで様々です。

mixed

Hackで開発する上で一番厄介で、なるべく利用して欲しくないのがこのmixedです。
いろんな型に加え、nullとvoidが許容されます。
mixedが記述されると、様々な手法でTypecheckerに理解可能なコードに書き直す必要があります。

下記のコードを例にしましょう。

  public function mixedParameter(mixed $param): string {
    return $param;
  }

引数にmixedを使い、そのまま返却している例です。
これはこのままだとTypeErrorになるため処理が実行できません。
$paramが文字列かどうかを保証するコードに変更しなければいけません。

下記のコードは問題がないコードです。

  public function mixedParameter(mixed $param): string {
    if($param is string) {
      return $param;
    }
    return '';
  }

invariantを利用することもできます。
mixedは使えば使うほど分岐処理などが増えていきますので、
注意が必要です。

  public function mixedParameter(mixed $param): string {
    invariant($param is string, 'Type Error.');
    return $param;
  }

nonnull

nullではないことを表すものです。
?nonnullにすると、mixedと同じ意味になります

  public function nullableNonnull(): nonnull {
    return 1234;
  }

num

intとfloatが利用できる型です。
以下のは問題なく動作します。

  public function returnNum(): num {
    if (true) {
      return 1.0;
    }
    return 1234;
  }

arraykey

intとstringが利用できる型です。

  public function returnKey(): arraykey {
    if (true) {
      return 'hello';
    }
    return 1234;
  }

callable

PHPのものと意味は同じですが、記述方法が異なります。
HackではcallableだけではTypecheckerでOKになりません。
callableなものでも無名関数の引数・型、無名関数の戻りの宣言しなければなりません。
またPHPの場合は __invokeを実装したクラスも許容されていますが、
Hackの場合は __invokeが実装されていてもcallableにはなりません。

  public function returnCallable(): (function(int): int) {
    return function(int $int) {
      return 1;
    };
  }

Tuple

多値をあらわすものです。
難しい型ではありません。

  public function returnTuple(): (int, string) {
    return tuple(1, 'testing');
  }

Classname

ライブラリ開発などで多用するであろう型です。
className::classを返却したり引数に利用できるところで利用できます。
下記のはものはstdClassの例です。

  public function returnClassname(): classname<\stdClass> {
    return \stdClass::class;
  }

Genericsを利用することで、様々なクラス名を扱うこともできます。

  public function returnGenericsClass<T as classname<T>>(T $name): T {
    return $name;
  }

今回は型の紹介のみでした。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?