Effictive Scala(2)

来源:互联网 发布:javascript定义数组 编辑:程序博客网 时间:2024/06/09 16:34

Effictive Scala(2)

变型

变型(Variance)发生在发型与子类型化(subtyping)结合的时候。与容器类型的子类型化有关,它们定义了对所包含的类型如何子类型化。因为scala有声明点变型(declaration variance)注释,公共库的作者–特别是集合–必须有丰富的注释器。这些注释对共享代码的可用性很重要,但滥用也会很危险。

不可变(invariants)是scala类型系统中高级部分,但也是必须的一面,应该使用广泛的(并且正确的),它有助于子类型化的应用。

不可变集合应该是斜变的。方法接受的类型能够应该适当的降级。

    trait Collection[T] {        def add[U >: T](other: U): Collection[U]    }

可变(mutable)集合应该是不可变的(invariant)。斜变对于可变集合是无效的。

    trait HashSet[+T] {        def add[U >: T] (item: U)    }    下面的类型层级:    trait Mammal    trait Dog extends Mammal    trait Cat extends Mammal    如果我现在有一个狗的HashSet:    val dogs: HashSet[Dog]    当它为一个哺乳动物的Set,增加一只猫(cat)    val mamals: HashSet[Mammal] =dogs    mammals.add(new Cat{})    这将不再是一个只存储狗的HashSet

类型别名

使用类型别名。 当他们提供了便捷的命名或阐明意图时,但对于自解释类型不要使用类型别名。

比如:    () => Int比以下定义的别名IntMaker更清晰    type IntMaker = () => Int    IntMaker但,下面的别名:    class ConcurrentPool[K, V]{        type Queue = ConcurrentLinkedQueue[V]        type Map = ConcurrentHashMap[K, Queue]        ..    }    有助于交流的目的并使得更加简短    当使用类型别名的时候不要使用子类型化(subtyping)    trait SocketFactory extends (SocketAddress => Socket)    SocketFactory 是一个生产Socket的方法。使用一个类型别名更好:    type SocketFactory = SocketAddress => Socket    我们现在可以对SocketFactory类型的值,提供函数字面量(function literals),也可以使用函数组合:    val addrToInet: SocketAddress => Long    val inetToSocket: Long => Socket    val factory: SocketFactory = addrToInet andThen inentToSocket    类型别名通过用package object 将名字绑定在顶层:    package com.twitter    package object net {        type SocketFactory = (SocketAddress) => Socket    }    注意类型别名不是新类型--他们等价于在语法上的用别名代替了原类型。

隐式转换

隐式转换是类型系统里一个强大的功能,但应当谨慎的使用。它们有复杂的解决规则为难你,通过简单的语法检查,领会实际发生什么。在下面的场景使用隐式转换:

1.扩展或增加一个scala风格的集合
2.适配或扩展一个对象
3.通过提供约束证据来加强类型安全。
4.To provided type evidence
5.For Manifests

如果你发现自己在用隐式转换,总要问问自己是否不使用这种方式也可以达到目的。

不要使用隐式转换对来年各个相似的数据类型做自动转换(例如,把list转换为stream)。

0 0
原创粉丝点击