W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
泛型可以用于你習(xí)慣于用Hack編程的許多實體,包括類,函數(shù),方法,接口,類型別名和特性。
考慮下面的例子,其中Stack是一個具有一個類型參數(shù)的泛型類T:
<?hh
namespace Hack\UserDocumentation\Generics\Entities\Examples\Classes;
class StackUnderflowException extends \Exception {}
class Stack<T> {
private array<T> $stack;
private int $stackPtr;
public function __construct() {
$this->stackPtr = 0;
$this->stack = array();
}
public function push(T $value): void {
$this->stack[$this->stackPtr++] = $value;
}
public function pop(): T {
if ($this->stackPtr > 0) {
return $this->stack[--$this->stackPtr];
} else {
throw new StackUnderflowException();
}
}
}
function useIntStack(Stack<int> $stInt): void {
$stInt->push(10);
$stInt->push(20);
$stInt->push(30);
echo 'pop => ' . $stInt->pop() . "\n";
$stInt->push(10.5); // rejected as not being type-safe
echo 'pop => ' . $stInt->pop() . "\n";
}
function run(): void {
$s = new Stack();
$s->push(5);
useIntStack($s);
}
run();
Output
pop => 30
pop => 10.5
如圖所示,type參數(shù)T用于實例屬性聲明中$stack,作為實例方法的參數(shù)類型push,以及作為實例方法的返回類型pop。請注意,雖然push并pop使用類型參數(shù),但它們本身不是通用方法。
該行$stInt->push(10.5);嘗試push使用非int參數(shù)進(jìn)行調(diào)用。這是被拒絕的,因為$stInt是一堆int,我們正試圖推一個float。
下面是一個泛型函數(shù)的例子maxVal,有一個類型參數(shù)T:
<?hh
namespace Hack\UserDocumentation\Generics\Entities\Examples\Functions;
function maxVal<T>(T $p1, T $p2): T {
return $p1 > $p2 ? $p1 : $p2;
}
function run(): void {
var_dump(maxVal(10, 20));
var_dump(maxVal(15.6, -20.78));
var_dump(maxVal('red', 'green'));
}
run();
Output
int(20)
float(15.6)
string(3) "red"
該函數(shù)返回傳遞給它的兩個參數(shù)中較大的一個。在調(diào)用的情況下maxVal(10, 20),如果這兩個參數(shù)的類型都是int,則推斷為與類型參數(shù)對應(yīng)的類型T,并int返回一個值。在呼叫的情況下maxVal(15.6, -20.78),T被推斷為float,而在maxVal('red', 'green'),T被推斷為string。
雖然push和pop方法在Stack上面的類示例中的泛型類中定義,但它們本身并不是泛型的。它們已經(jīng)綁定到類類型參數(shù)T。
就像泛型函數(shù)一樣,泛型方法也有自己的類型參數(shù),即使該方法不屬于泛型類??紤]庫類型Pair:
final class Pair<Tv1, Tv2> implements ConstVector<mixed> {
// …
public function map<Tu>( (function(Tv): Tu) $callback ): Vector<Tu>
public function zip<Tu>(Traversable<Tu> $iter): Vector<Pair<mixed, Tu>>
public function zip<Tu>( Traversable<Tu> $iterable ): Vector<Pair<mixed, Tu>>
}
正如我們所看到的,方法map和zip每個方法都有一個通用參數(shù)Tu,它的類型是從傳遞給每個方法的參數(shù)中推斷出來的。這個泛型參數(shù)意味著我們可以在方法的參數(shù)或返回類型中使用它。請注意,泛型方法具有與類不同的類型參數(shù)(例如Tvvs Tu)。如果綁定了這些方法Tv,那么我們就不需要方法的泛型參數(shù),因為它已經(jīng)綁定到了類的類型參數(shù)。
像一個類一樣,一個接口可以有類型參數(shù); 例如:
<?hh
namespace Hack\UserDocumentation\Generics\Entities\Examples\Interfaces;
interface MyCollection<T> {
public function put(T $item): void;
public function get(): ?T;
}
class MyStack<T> implements MyCollection<T> {
private Vector<T> $storage;
public function __construct() {
$this->storage = Vector {};
}
public function put(T $item): void {
$this->storage[] = $item;
}
public function get(): ?T {
// LIFO
return $this->storage->count() > 0 ? $this->storage[0] : null;
}
}
class MyQueue<T> implements MyCollection<T> {
private Vector<T> $storage;
public function __construct() {
$this->storage = Vector {};
}
public function put(T $item): void {
$this->storage[] = $item;
}
public function get(): ?T {
// FIFO
return $this->storage->count() > 0
? $this->storage[$this->storage->count() - 1]
: null;
}
}
function processCollection<T>(MyCollection<T> $p1): void {
var_dump($p1->get());
}
function run(): void {
$s = new MyStack();
$s->put(5);
$s->put(9);
$s->put(3);
processCollection($s);
$q = new MyQueue();
$q->put(5);
$q->put(9);
$q->put(3);
processCollection($q);
}
run();
Output
int(5)
int(3)
在這里,我們有通用的堆棧和隊列類,每個類都實現(xiàn)相同的通用接口,使這些類能夠以一致的方式存儲和檢索元素。
像通用類一樣,通用特征具有類型參數(shù)列表; 例如:
trait MyTrait<T1, T2> {
public static function f(T1 $value): void {
// ...
}
類型別名可以是任何類型的別名,包括泛型類型。例如:
newtype Matrix<T> = Vector<Vector<T>>;
type Serialized<T> = string; // T is not used
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: