有了泛型,就可以编写出更为简洁,通用,抽象的代码.
V的泛型目前支持三种:泛型函数,泛型结构体,泛型方法.
在泛型函数中,所有普通类型能使用的场景,泛型也应该要能使用,
泛型跟普通类型一样,可以作为:
- 函数参数的类型
- 函数返回值的类型
- 函数不确定个数参数的类型
- 函数数组参数的类型
- 数组的类型
- 多维数组的类型
- 固定大小数组的类型
- 泛型支持类型系统中的:所有基本类型,数组,字典类型,信道chan的类型
- 甚至泛型函数和泛型结构体也可以组合起来使用
- 其他各种普通类型能用的场景…
简洁方式只有泛型在函数参数中有使用才可以,编译器会自动根据参数具体的类型,传递类型信息给函数,让调用泛型函数看起来像是调用普通函数那样.
//泛型函数
fn get<T>(typ T) T {
return typ
}
//多个类型的泛型函数,参数,函数体,返回值都可以使用
fn get_multi<T,U>(typ T,user U) (T,U) {
println(typ)
println(user)
return typ,user
}
fn main() {
a1 := get<string>('hello') //标准的泛型调用方式,带<T>
a2 := get<int>(1)
println(a1)
println(a2)
b1 := get('hello') //简短的泛型调用方式,不用带<T>
b2 := get(1)
println(b1)
println(b2)
x,y:=get_multi<int,f64>(2,2.2) //标准的泛型调用方式,带<T,U>
println('x is $x,y is $y')
c,d:=get_multi(3,3.3) //简短的泛型调用方式,不用带<T,U>
println('c is $c,d is $d')
在泛型结构体中,所有普通类型能使用的场景,泛型也应该要能使用,
泛型跟普通类型一样,在结构体中可以作为:
- 结构体字段的类型
- 结构体的引用类型&
- 结构体函数类型字段的参数或返回值
- 泛型函数的嵌套使用
- 泛型结构体的嵌套使用
- 泛型结构体的泛型方法
- 甚至泛型函数和泛型结构体也可以组合起来使用
- 其他各种普通类型能用的场景…
泛型方法基本跟泛型函数一样,唯一的差别是如果结构体也是泛型结构体,方法的接收者也都要带上泛型符号.
module main
struct Point {
mut:
x int = 1
y int = 1
//结构体是普通结构体,方法是泛型方法
fn (mut p Point) translate<T>(x T, y T) {
p.x += x
p.y += y
}
struct Abc<T> {
value T
}
//结构体是泛型结构体,方法的接收者都要带上<T>
fn (s Abc<T>) get_value() T { //泛型结构体的泛型方法
return s.value
}
fn (s Abc<T>) normal_fn() { //泛型结构体的普通方法
println('from normal_fn')
}
fn main() {
mut pot := Point{}
pot.translate<int>(1, 3)
println(pot)
s := Abc<string>{'hello'}
println(s.get_value())
s.normal_fn()
这种实现方式的优点是性能好,没有运行时开销,缺点是如果实际调用到的类型很多,穷举后生成的普通函数和普通结构体也会很多,编译后的可执行文件会变大.
这种取舍在所难免,不过运行快最重要,可执行文件变大,只要不是太夸张,还是可以接受的.
V泛型代码:
生成的C代码:
// V typedefs:
typedef struct main__Info_T_bool main__Info_T_bool;
typedef struct main__Info_T_int main__Info_T_int;
typedef struct main__Info_T_f32 main__Info_T_f32;
bool data;
};
struct main__Info_T_int {
int data;
};
struct main__Info_T_f32 {
f32 data;
};
VV_LOCAL_SYMBOL int main__simple_T_int(int p) {
return p;
}
VV_LOCAL_SYMBOL string main__simple_T_string(string p) {
return p;
}
VV_LOCAL_SYMBOL Array_int main__simple_T_Array_int(Array_int p) {
return p;
}
VV_LOCAL_SYMBOL Map_string_string main__simple_T_Map_string_string(Map_string_string p) {
return p;
}
VV_LOCAL_SYMBOL void main__main(void) {
main__simple_T_int(1);
main__simple_T_int(1 + 0);
main__simple_T_string(_SLIT("g"));
main__simple_T_Array_int(new_array_from_c_array(1, 1, sizeof(int), _MOV((int[1]){1})));
main__simple_T_Map_string_string(new_map_init(&map_hash_string, &map_eq_string, &map_clone_string, &map_free_string, 1, sizeof(string), sizeof(string), _MOV((string[1]){_SLIT("a"), }), _MOV((string[1]){_SLIT("b"), })));
main__Info_T_bool info1 = (main__Info_T_bool){.data = true,};
main__Info_T_int info2 = (main__Info_T_int){.data = 1,};
main__Info_T_f32 info3 = (main__Info_T_f32){.data = 1.1,};
println( str_intp(4, _MOV((StrIntpData[]){{_SLIT0, 0xfe10, {.d_s = main__Info_T_bool_str(info1)}}, {_SLIT(","), 0xfe10, {.d_s = main__Info_T_int_str(info2)}}, {_SLIT(","), 0xfe10, {.d_s = main__Info_T_f32_str(info3)}}, {_SLIT0, 0, { .d_c = 0 }}})) );
- 对类型进行where限定,给类型增加条件限定
- 泛型跟类型系统中的联合类型,接口类型之间的结合使用