zoukankan      html  css  js  c++  java
  • scala学习手记22

    java 的代码中多少有些不是很严谨的内容,比如下面的这段代码:

    public class Trouble {
        public static void main(String[] args) {
            Integer[] arr1 = new Integer[2];
            arr1[0] = new Integer(1);
            Object[] arr2 = arr1;
            arr2[1] = new Double(2.0);
            for (Integer i : arr1) {
                System.out.println(i);
            }
        }
    }

    这段代码是可以通过编译的。但是在执行的时候会报错。

    image

    使用scala编写类似的代码(印象中类似的代码之前也提到过):

    var arr1:Array[Int] = new Array[Int](3)
    var arr2:Array[Any] = arr1

    这段程序在编译期就会报错:因为不能将显式声明为Int型的数组赋给Any类型的数组。看一下报错信息:

    image

    将子类对象赋值给超类称为协变;将超类对象赋值给子类称为逆变。默认情况下,scala对这两种“变”都不支持。

    不过有时候真的很需要协变的支持——不然继承的实现价值会小很多。看一下下面的代码:

    class Pet(val name: String) {
      override def toString() = name
    }
    
    class Dog(override val name: String) extends Pet(name)
    
    class Cat(override val name: String) extends Pet(name)
    
    def playWithPets(pets: Array[Pet]) {println("play with " + pets.mkString(","))}

    在上面的代码里定义了一个playWithPets方法,因为我们既想遛狗又想逗猫,有事没事还想和海豚一起游泳。如果不能支持协变,那怎么办,总不能写PlayWithDog、PlayWithCat、PlayWithDelphin、PlayWithXXX…无穷匮也了。

    先勉强试试下面的代码:

    val dogs = Array(new Dog("Rover"), new Dog("Comet"))
    
    playWithPets(dogs)

    根据前面的经验,这段代码在编译期就会报错:

    image

    看吧,遛狗都不行,别说逗猫调戏海豚什么的了。

    既然说到这里了,那么肯定会有解决的方法,修改下playWithPets方法:

    def playWithPets[T <: Pet](pets: Array[T]){}

    这里用特殊的语法定义了playWithPets()。T<:Pet表示T所代表的类派生自Pet。通过这样的语法,我们告诉scala,我们需要的参数是Pet类型的数组或者继承自Pet类型的类的数组,换句话说就是为参数类型指定了一个上界,就是。这样调整后再编译执行就没问题了:

    image

    还有另一个特殊的语法“P>:Dog”。很明显的,可以类推出来这是为参数类型指定了一个下界。举个例子:偷猫逗狗结束了,需要把猫狗关进笼子里,可是没有猫笼子了,狗笼还有富余,那怎么办,把猫关进狗笼子啊(宠物都是单间待遇)。示例代码如下:

    def sendToDogCaf[T >: Dog](pet: Pet) {
      println("send " + pet + "to Dog's cafe")
    }
    
    sendToDogCaf(new Cat("Lily"))
    sendToDogCaf(new Pet("Rabbit"))

    执行结果如下图:

    image

    就是这样,上面演示了如何在方法定义里控制方法的参数。

    不过,如果是GM的话,当然也可以用杂兵下副本——如果是容器类的作者,当然也可以控制参数类型的可变性。如下面这段代码:

    class MyList[+T]//...
    
    var list1 = new MyList[int]
    var list2: MyList[Any] = null
    list2 = list1 // OK

    这里,+T告诉Scala允许协变;换句话说,在类型检查期间,让Scala接收某个类型或者其基类型。这样,就可以将MyList[Int]赋给MyList[Any]。对于Array[Int]而言,这是不可以的。不过,对于List(Scala程序库中实现的函数式List)而言,这是可以的。

    类似的,参数化类型用-T替换T,就可以让Scala支持类型逆变。

    ###########

  • 相关阅读:
    POJ 3672 水题......
    POJ 3279 枚举?
    STL
    241. Different Ways to Add Parentheses
    282. Expression Add Operators
    169. Majority Element
    Weekly Contest 121
    927. Three Equal Parts
    910. Smallest Range II
    921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/amunote/p/5693782.html
Copyright © 2011-2022 走看看