本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1.什么是范型?
泛型字面理解“广泛适用的类型”,其本质是指类型参数化,即可以将类型当作参数传递给一个类或者是方法。 允许在定义类、接口、方法时使用类型形参,分别称为泛型类、泛型接口、泛型方法,当使用时 指定具体类型。 所有使用该泛型参数的地方都被统一化,保证类型一致。
范型是不是看着像弱类型? 两者是有着本质区别的,弱类型是对编译系统说:这个变量什么类型都可以,你自己看着办吧!就像js,不指定类型; 而范型是对编译系统说:这个变量按说好的来,说这次是啥类型这个变量就是啥类型。
2.为什么要用范型?
参数化多态(Parametric Polymorphism),根据实参生成不同的版本,支持任意数量的调用,即泛型,简言之,就是把元素类型变成了参数。 使用范型可以优化我们的代码。
**不明白?**哪里优化代码了?举个荔枝^_^
#这里是java的Map类的范型定义
/**
* An object that maps keys to values. A map cannot contain duplicate keys;
* each key can map to at most one value.
* ...
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
* ...
*/
public interface Map<K,V> {
...
V put(K key, V value);
...
V get(Object key);
...
}
#如果没有范型呢?
public interface StrMap {
...
String put(String key, String value);
...
String get(String key);
...
}
...
public interface IntegerMap {
...
Integer put(Integer key, Integer value);
...
Integer get(Object key);
...
}
#所有的类型全部穷举一遍,又累又冗余,万一要改是不是要疯?
或者像下面这样:
3.Golang没有范型不是一样用么?
Go是一门强类型语言,意味着程序中的每个变量和值都有某种特定的类型,例如int、string等。没有泛型,很多人以此“鄙视”Golang。而目前由于泛型支持的复杂性,Golang的设计和实现者并没有把这个泛型支持作为紧急需要增加的特性 而是建议大家使用接口来实现类似范型的功能。很多人因此而十分不满,认为没有泛型增加了很多工作量。 好消息是Go1.17中已经发布了泛型的体验版,这一功能也是为1.18版本泛型正式实装做铺垫。
Golang1.17中泛型的要点
- 函数可以通过type关键字引入额外的类型参数(type parameters)列表:func F(type T)(p T) { ... } 。
- 这些类型参数可以像一般的参数一样在函数体中使用。
- 类型也可以拥有类型参数列表:type M(type T) []T。
- 每个类型参数可以拥有一个约束:func F(type T Constraint)(p T) { ... }。
- 使用interface来描述类型的约束。
- 被用作类型约束的interface可以拥有一个预声明类型列表,限制了实现此接口的类型的基础类型。
- 使用泛型函数或类型时需要传入类型实参。
- 一般情况下,类型推断允许用户在调用泛型函数时省略类型实参。
- 如果类型参数具有类型约束,则类型实参必须实现接口。
- 泛型函数只允许进行类型约束所规定的操作。
#例如:原来的加法函数
func Add(i1, i2 int) int
func AddFloat(i1, i2 float) float
#golang 下的范型定义:
func Add[T any](i1, i2 T) T
4.泛型困境
泛型和其他特性一样不是只有好处,为编程语言加入泛型会遇到需要权衡的两难问题。语言的设计者需要在编程效率、编译速度和运行速度三者进行权衡和选择,编程语言要选择牺牲一个而保留另外两个。 在2009年的时候,Russ Cox提出来的一个关于泛型的问题叫做泛型困境,用来收集人们对Golang中泛型的一些意见和建议,对Golang泛型设计当中的问题进行解释,并表示他们并不急于去实现泛型,因为还没有找到一个合适的实现方案去解决困境。 而泛型困境的本质是,关于泛型,你想要缓慢的程序员、缓慢的编译器和臃肿的二进制文件,还是缓慢的执行时间。简单来说就是:要么苦了程序员,要么苦了编绎器,要么降低运行时效率。