W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
泛型可以用于你習(xí)慣于用Hack編程的許多實(shí)體,包括類(lèi),函數(shù),方法,接口,類(lèi)型別名和特性。
考慮下面的例子,其中Stack是一個(gè)具有一個(gè)類(lèi)型參數(shù)的泛型類(lèi)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用于實(shí)例屬性聲明中$stack,作為實(shí)例方法的參數(shù)類(lèi)型push,以及作為實(shí)例方法的返回類(lèi)型pop。請(qǐng)注意,雖然push并pop使用類(lèi)型參數(shù),但它們本身不是通用方法。
該行$stInt->push(10.5);嘗試push使用非int參數(shù)進(jìn)行調(diào)用。這是被拒絕的,因?yàn)?stInt是一堆int,我們正試圖推一個(gè)float。
下面是一個(gè)泛型函數(shù)的例子maxVal,有一個(gè)類(lèi)型參數(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ù)返回傳遞給它的兩個(gè)參數(shù)中較大的一個(gè)。在調(diào)用的情況下maxVal(10, 20),如果這兩個(gè)參數(shù)的類(lèi)型都是int,則推斷為與類(lèi)型參數(shù)對(duì)應(yīng)的類(lèi)型T,并int返回一個(gè)值。在呼叫的情況下maxVal(15.6, -20.78),T被推斷為float,而在maxVal('red', 'green'),T被推斷為string。
雖然push和pop方法在Stack上面的類(lèi)示例中的泛型類(lèi)中定義,但它們本身并不是泛型的。它們已經(jīng)綁定到類(lèi)類(lèi)型參數(shù)T。
就像泛型函數(shù)一樣,泛型方法也有自己的類(lèi)型參數(shù),即使該方法不屬于泛型類(lèi)??紤]庫(kù)類(lèi)型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每個(gè)方法都有一個(gè)通用參數(shù)Tu,它的類(lèi)型是從傳遞給每個(gè)方法的參數(shù)中推斷出來(lái)的。這個(gè)泛型參數(shù)意味著我們可以在方法的參數(shù)或返回類(lèi)型中使用它。請(qǐng)注意,泛型方法具有與類(lèi)不同的類(lèi)型參數(shù)(例如Tvvs Tu)。如果綁定了這些方法Tv,那么我們就不需要方法的泛型參數(shù),因?yàn)樗呀?jīng)綁定到了類(lèi)的類(lèi)型參數(shù)。
像一個(gè)類(lèi)一樣,一個(gè)接口可以有類(lèi)型參數(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)
在這里,我們有通用的堆棧和隊(duì)列類(lèi),每個(gè)類(lèi)都實(shí)現(xiàn)相同的通用接口,使這些類(lèi)能夠以一致的方式存儲(chǔ)和檢索元素。
像通用類(lèi)一樣,通用特征具有類(lèi)型參數(shù)列表; 例如:
trait MyTrait<T1, T2> {
public static function f(T1 $value): void {
// ...
}
類(lèi)型別名可以是任何類(lèi)型的別名,包括泛型類(lèi)型。例如:
newtype Matrix<T> = Vector<Vector<T>>;
type Serialized<T> = string; // T is not used
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: