FAQ
我理解的协变是有类型S和T, S 是 T的子类,如果有声明参数类型为[+S]的话,Iterable[S] 也是 Iterable[T]的之类,逆变就是相反.
但是什么情况下会用这样的特性呢,没有想出来好的应用场景.

--
您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com
要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/groups/opt_out。

Search Discussions

  • 黄鑫 at May 2, 2013 at 5:31 pm
    move(Animal a)

    move(Dog d)


    在 2013年5月2日下午11:49,firefoxmmx <firefoxmmx@gmail.com>写道:
    我理解的协变是有类型S和T, S 是 T的子类,如果有声明参数类型为[+S]的话,Iterable[S] 也是
    Iterable[T]的之类,逆变就是相反.
    但是什么情况下会用这样的特性呢,没有想出来好的应用场景.

    --
    您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
    要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com
    要查看更多选项,请访问 https://groups.google.com/groups/opt_out。


    --
    thanks!.

    --
    您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
    要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com
    要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
  • Nicholas Ren at May 3, 2013 at 12:57 am
    协变的应用场景:

    Given :
    class Animal
    class Dog <: Animal

    And 有一个自定义的迭代器类 Iterable[+S]
    Then
    Iterable[Dog] 是 Iterable[Animal] 的子类型

    逆变的应用场景:

    Given
    class Animal
    class Dog <: Animal

    class Shit
    class Dogshit <: Shit

    And 有一个function类型,接受类型为P的参数,返回类型为R的结果

    trait Function[-P, +R] {
    def apply(p: P): R
    }
    Then
    Function[Animal, DogShit] 是 Function[Dog, Shit]的子类型


    例子有点恶心,但是应该很好理解 ;)

    总结一下这个应用场景,有两个函数类型
    A: Function[P1, R1]
    B: Function[P2, R2],
    当P1是P2的父类型,R1是R2子类型时,A 就是 B 的子类型。


    --
    Nicholas Ren (任晓君)

    ThoughtWorks | Xi'an | GMT+8

    On Friday, May 3, 2013 at 1:31 AM, 黄鑫 wrote:

    move(Animal a)

    move(Dog d)


    在 2013年5月2日下午11:49,firefoxmmx (mailto:firefoxmmx@gmail.com)>写道:
    我理解的协变是有类型S和T, S 是 T的子类,如果有声明参数类型为[+S]的话,Iterable[S] 也是 Iterable[T]的之类,逆变就是相反.
    但是什么情况下会用这样的特性呢,没有想出来好的应用场景.

    --
    您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
    要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com (mailto:scalacn%2bunsubscribe@googlegroups.com)。
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com (mailto:scalacn@googlegroups.com)。
    要查看更多选项,请访问 https://groups.google.com/groups/opt_out。


    --
    thanks!.

    --
    您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
    要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com (mailto:scalacn+unsubscribe@googlegroups.com)。
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com (mailto:scalacn@googlegroups.com)。
    要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
    --
    您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
    要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com
    要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
  • Xuefeng Wu at May 3, 2013 at 2:19 am
    协变逆变确实不好理解,因为java没有这个概念。实际上java有范型参数但不强制,用得也不深入和广泛。
    C# 4现在也引入协变逆变概念了,协变逆变适用于范型参数。

    最能体现协变逆变的例子其实是lambda表达式。
    比如scala定义了scala.Function1[-T,+R], 展开成lambda表达的意思是 -T => +R

    假如我有一个榨汁机,它能把苹果榨成苹果汁,把橘子榨成橘子汁。

    def extractor[T <: Fruit,R <: Drink](v:T,f: T => R):R = {
    f(v)
    }

    这里又用了个类型上界,T和R都有各自的类型上界,也就是必须是这些上界的子类。

    再定义一些苹果和汁的类型:

    class Fruit
    class Apple extends Fruit
    class HongFuShi extends Apple

    class Drink
    class Juice extends Drink
    class AppleJuice extends Juice

    好了,这个榨汁机有个简单地把苹果榨成汁的功能:
    def appleOp = (a:Apple) => new Juice


    因为-T是逆变,可以放苹果或红富士,但不能放水果
    val juice:Juice = extractor(new Apple, appleOp)
    val juice2:Juice = extractor(new HongFuShi, appleOp)

    val juice3:Juice = extractor(new Fruit, appleOp)
    呃~ 编译失败,提示type mismatch; found : act.Apple => act.Juice required: act.Fruit
    => act.Juice
    这个错误提示你要倒过来看,因为我们先有appleOp操作,再放不同水果,那么这个意思就是放水果是不行的,你可以放红富士

    这是逆变,不接受父类,接受子类了。
    再来看协变,它能容父类不能容子类。

    因为我们的榨汁功能是榨出汁这个饮料,可以直接去接汁,也可以接饮料,但不能接苹果汁。
    val juice:Juice = extractor(new HongFuShi, appleOp)
    val drink:Drink = extractor(new HongFuShi, appleOp)

    val appleJuice:AppleJuice = extractor(new HongFuShi, appleOp)
    呃~ 又编译失败,提示type mismatch; found : act.Apple => act.Juice required: ? =>
    act.AppleJuice
    它不产出苹果汁


    2013/5/2 firefoxmmx <firefoxmmx@gmail.com>
    我理解的协变是有类型S和T, S 是 T的子类,如果有声明参数类型为[+S]的话,Iterable[S] 也是
    Iterable[T]的之类,逆变就是相反.
    但是什么情况下会用这样的特性呢,没有想出来好的应用场景.

    --
    您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
    要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com
    要查看更多选项,请访问 https://groups.google.com/groups/opt_out。


    --

    吴雪峰/ Alan 敬上

    --
    您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
    要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com
    要查看更多选项,请访问 https://groups.google.com/groups/opt_out。
  • Firefoxmmx at May 3, 2013 at 3:55 am
    在 2013年5月3日 星期五 10:19:13,Xuefeng Wu 写道:


    协变逆变确实不好理解,因为java没有这个概念。实际上java有范型参数但不强制,用得也不深
    入和广泛。
    C# 4现在也引入协变逆变概念了,协变逆变适用于范型参数。


    最能体现协变逆变的例子其实是lambda表达式。
    比如scala定义了scala.Function1[-T,+R], 展开成lambda表达的意思是 -T => +R


    假如我有一个榨汁机,它能把苹果榨成苹果汁,把橘子榨成橘子汁。


    def extractor[T <: Fruit,R <: Drink](v:T,f: T => R):R = {
    f(v)
    }


    这里又用了个类型上界,T和R都有各自的类型上界,也就是必须是这些上界的子类。


    再定义一些苹果和汁的类型:


    class Fruit
    class Apple extends Fruit
    class HongFuShi extends Apple


    class Drink
    class Juice extends Drink
    class AppleJuice extends Juice


    好了,这个榨汁机有个简单地把苹果榨成汁的功能:
    def appleOp = (a:Apple) => new Juice





    因为-T是逆变,可以放苹果或红富士,但不能放水果
    val juice:Juice = extractor(new Apple, appleOp)

    val juice2:Juice = extractor(new HongFuShi, appleOp)



    val juice3:Juice = extractor(new Fruit, appleOp)
    呃~ 编译失败,提示type mismatch; found : act.Apple => act.Juice required: act.Fruit
    => act.Juice
    这个错误提示你要倒过来看,因为我们先有appleOp操作,再放不同水果,那么这个意思就是放
    水果是不行的,你可以放红富士


    这是逆变,不接受父类,接受子类了。
    再来看协变,它能容父类不能容子类。


    因为我们的榨汁功能是榨出汁这个饮料,可以直接去接汁,也可以接饮料,但不能接苹果汁。
    val juice:Juice = extractor(new HongFuShi, appleOp)


    val drink:Drink = extractor(new HongFuShi, appleOp)



    val appleJuice:AppleJuice = extractor(new HongFuShi, appleOp)

    呃~ 又编译失败,提示type mismatch; found : act.Apple => act.Juice required: ? =>
    act.AppleJuice
    它不产出苹果汁






    2013/5/2 firefoxmmx [1]>


    我理解的协变是有类型S和T, S 是 T的子类,如果有声明参数类型为[+S]的话,Iterable[S] 也是
    Iterable[T]的之类,逆变就是相反.但是什么情况下会用这样的特性呢,没有想出来好的应用场景.


    scalacn+unsubscribe@googlegroups.com[2]。要向此网上论坛发帖,请发送电子邮件至
    scalacn@googlegroups.com[3]。要查看更多选项,请访问
    https://groups.google.com/groups/opt_out[4]。








    --




    吴雪峰/ Alan 敬上


    -- 您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。要退订此论坛并停
    止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com。要查看更多选项,请
    访问 https://groups.google.com/groups/opt_out。[5]

    很感谢你们的热心回答,我已经知道 这个的用法了,谢谢.





    --------
    [1] mailto:firefoxmmx@gmail.com
    [2] mailto:scalacn%2bunsubscribe@googlegroups.com
    [3] mailto:scalacn@googlegroups.com
    [4] https://groups.google.com/groups/opt_out
    [5] https://groups.google.com/groups/opt_out。

    --
    您收到此邮件是因为您订阅了 Google 网上论坛的“Scala中文社区”论坛。
    要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到 scalacn+unsubscribe@googlegroups.com
    要向此网上论坛发帖,请发送电子邮件至 scalacn@googlegroups.com
    要查看更多选项,请访问 https://groups.google.com/groups/opt_out。

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupscalacn @
postedMay 2, '13 at 4:07p
activeMay 3, '13 at 3:55a
posts5
users4

People

Translate

site design / logo © 2019 Grokbase