Scala泛型
admin
2023-07-29 11:40:09
0

简单回顾泛型

java中可使用泛型进行编程,一个简单的泛型例子如下:

List strList = new ArrayList();
strList.add("one");
strList.add("two");
strList.add("three");

String one = strList.get(0); // 泛型拿数据不必进行类型转换,不使用泛型的话需要对类型进行转换

scala的泛型

scala中的泛型称为类型参数化(type parameterlization)。语法跟java不一样,使用”[]”表示类型。

一个使用类型参数化的函数:

def position[A](xs: List[A], value: A): Int = {
    xs.indexOf(value)
}

position(List(1,2,3), 1) // 0
position(List("one", "two", "three"), "two") // 1

稍微复杂点的类型参数化,实现一个map函数,需要一个List和一个函数作为参数:

普通的map方法:

List(1,2,3) map { _ * 2 }  // List[Int] = List(2,4,6)
List(1,2,3) map { _ + "2" }  // List[String] = List(12, 22, 32)

使用泛型实现的map方法:

def map[A,B](list:List[A], func: A => B) = list.map(func)

map(List(1,2,3), { num: Int => num + "2" }) // List[String] = List(12, 22, 32)
map(List(1,2,3), { num: Int => num * 2 }) // List[Int] = List(2, 4, 6)

上限和下限

scala跟java一样,也提供了上限(upper bounds)和下限(lower bounds)功能。

上限(upper bounds)

java中上限的使用如下:



通配符形式

scala写法:

[T <: AnyRef]

通配符形式
[_ <: AnyRef]

上限的一些例子:

public void upperBound(List list) {
    Object obj = list.get(0); // Number是Object的子类,使用Object可以代替Number。
    Number num = list.get(0);
    Integet i = list.get(0); // compile error
    list.add(new Integer(1)); // compile error
}

上限做参数,set的话不能确定具体的类型,所以会报编译错误。get的话得到的结果的类型的下限为参数的上限。相当于使用了上限参数的话,该参数就变成了只读参数,类似生产者,只提供数据。

scala版本:

def upperBound[A <: Animal](list: ListBuffer[A]): Unit = { 
    list += new Animal("123") // compile error
    val obj: AnyRef = list(0) // ok
    val a: Animal = list(0) // ok
    val a: Cat = list(0) // compile error
}

这里使用ListBuffer作为集合,ListBuffer的+=方法会在列表内部添加数据,不会产生一个新的List。如果使用List的话,:+操作符会在新生成的List中自动得到符合所有元素的类型。

List[Animal](new Cat()) :+ 1 // List[Any] = List(Cat@3f23a076, 1)

生成新的List会自动根据上下文得到新的泛型类型List[AnyRef]。

下限(lower bounds)



通配符形式

scala写法:

[T >: MyClass]

通配符形式
[_ >: MyClass]

下限的一些例子:

public static void lowerBound(List l) {
    l.add(new Integer(1));
    l.add(new Float(2));
    Object obj = l.get(0);
    Number num = l.get(0); // compile error
}

下限做参数,get方法只能用最宽泛的类型来获取数据,相当于get只提供了数据最小级别的访问权限。类似消费者,主要用来消费数据。

scala版本:

def lowerBound[A >: Animal](list: ListBuffer[A]): Unit = { 
    list += new Animal() // ok
    list += new Cat() // ok
    val obj: Any = list(0) // ok
    val obj: Animal = list(0) // compile error
}

协变和逆变

协变(covariance):对于一个带类型参数的类型,比如List[T],如果对A及其子类型B,满足List[B]也符合List[A]的子类型,那么就称为协变,用加号表示。比如 MyType[+A]

逆变(contravariance):如果List[A]是List[B]的子类型,用减号表示。比如MyType[+B]

如果一个类型支持协变或逆变,则称这个类型为可变的(variance)。否则称为不可变的(invariant)。

在java里,泛型类型都是不可变的,比如List并不是List的子类。

trait A[T]
class C[T] extends A[T]
class Parent; class Child extends Parent
val c:C[Parent] = new C[Parent] // ok
val c:C[Parent] = new C[Child]; // Child <: Parent, but class C is invariant in type T.

协变

上面的例子提示已经很明确了。类C是不可变的,改成协变即可。

trait A[+T]
class C[+T] extends A[T]
class Parent; class Child extends Parent
val c: C[Parent] = new C[Parent] // ok
val c: C[Parent] = new C[Child]  // ok

scala中List就是一个协变类。

val list:List[Parent] = List[Child](new Child())

逆变

逆变概念与协变相反。

trait A[-T]
class C[-T] extends A[T]
class Parent; class Child extends Parent
val c: C[Parent] = new C[Parent] // ok
val c: C[Child] = new C[Parent]  // ok

协变逆变注意点

逆变协变并不会被继承,父类声明为逆变或协变,子类如果想要保持,任需要声明:

trait A[+T]
class C[T] extends A[T] // C是不可变的,因为它不是逆变或协变。
class D[+T] extends A[T] // D是可变的,是协变
class E[-T] extends A[T] // E是可变的,是逆变


相关内容

热门资讯

7-11便利店起诉耐克新鞋配色... 封面新闻记者 赵奕 柴枫桔据路透社7月2日报道,跨国连锁零售公司7-Eleven(7-11)已在美国...
香港患者北上寻药:部分抗癌药内... 距离深圳福田口岸约十多分钟车程的深圳新风和睦家医院,开业仅有四年,肿瘤科中的中国香港患者占比达到75...
陈奕迅女儿回应父亲购买1.8亿... 近日,陈奕迅女儿陈康堤在接受采访时,首度回应了父亲购买约1.8亿(港元)豪宅一事。陈康堤表示:“他没...
福山:美国或衰落下去,最终将领... 【文/观察者网 冯雪】美国迎来建国250周年前夕,日裔美籍学者弗朗西斯·福山(Francis Fuk...
热水器调节不了温度 热水器无法调节水温,是不能调节温度的,可以通过调节水量开关和火力开关来调节水温。热水器有两个温度调节...
科龙冷藏柜的温度调节 冷藏柜的调节可以通过外置温度调节器来实现,在调节的时候注意温度要和环境温度相结合,档位越高表示温度越...
没有网线连接电视机的方法 对于没有网线连接电视机的情况,有以下几种方法可供选择。 1.使用WiFi连接器 现在市场上有很多...
电视机的普及方法 电视机是一种广泛使用的家庭娱乐设备。随着科技的发展,电视机不仅仅是一个娱乐平台,同时也被用于教育、新...
海尔电视机挂墙上的方法 如果你想要让你的海尔电视机挂在墙上,有一些重要的事情你需要考虑。首先,你需要确保你的电视机符合标准墙...
佛得角输了,但没有人会否认这场... 我想,这一刻会让很多人动容。佛得角2 : 3惜败阿根廷,止步世界杯淘汰赛。但看过的人都知道,这不只是...