今天要來談談 Generic。由於靜態語言對於宣告的類型有嚴格的規定,Generic 的出現則是讓這件事情變得更加彈性,可以將一套程式碼複用在不同類型的資料上。例如所謂 Generic class 或 Generic function 的參數就會除了一般的參數之外,也會有參數代表的是類型,也就是類型參數化。這樣子的好處是,就不用只是因為參數類型不同,就需要再撰寫一個很像的函式,例如把整數跟字串印出來的函數,可能邏輯上是完全一樣的,就不用特別寫像是 printInt
和 printStr
。待會我們就會來看一些例子囉!
typing
的 Library 來提供像是 List
、Tuple
、Dict
等等 Type hints 供我們使用。例如下面的程式碼,我們從 typing
引入了 Dict, Tuple, List
,而 Options
、Host
、Server
是 Type alias,可以讓我們自定義類型的別名以供後續使用,所以 connect
的參數 servers
就可以寫成 List[Server]
。-> None
表示返回的是 None
。from typing import Dict, Tuple, List
Options = Dict[str, str]
Host = Tuple[str, int]
Server = Tuple[Host, Options]
def connect(servers: List[Server]) -> None:
pass
T = TypeVar('T')
是定義了類型參數,而 Generic[T]
就是表示泛型,因此我們就可以在方法裡頭去標註類型參數了!T = TypeVar('T')
class LoggedVar(Generic[T]):
def set(self, new: T) -> None:
pass
def get(self) -> T:
pass
typing
有興趣的可以參考這裡囉!v interface{}
就是代表 v
可以是任何類型,而回傳也是任何類型。至於如何在程式裡頭去知道是什麼類型並做對應的事情呢?這裡用的是 Type switch,switch v.(type)
會去看傳入的 v
是不是 case 中的 Type,是的話就執行對應的程式。而 v.(int)
和 v.(float64)
是 Type assertion,例如 v.(int)
表示如果 v
是 int 就會得到真正這個 int 的值,假使不是 int
就會引發 panic。然而我們也可以這樣使用 i, ok := v.(int)
這樣就不會 panic,而是把是否是 int 這件事情存在 ok
之中囉!package main
import (
"reflect"
)
func Test(v interface{}) interface{} {
switch v.(type) {
case int:
return v.(int) + 10
case float64:
return v.(float64) + 22.3
}
return v
}