首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么Scala的不可变Set在其类型中不协变?

在 Scala 中,不可变集合(Set)是不可变的,这意味着它们的元素不能被修改。不可变集合的一个重要特性是它们是协变的,这意味着如果 A <: B(A 是 B 的子类型),那么 Set[A] 也是 Set[B] 的子类型。这种协变关系在 Scala 的集合类型中是通用的,包括可变集合和映射(Map)。

然而,在 Scala 的类型系统中,不可变集合的协变性并不直接体现在类型参数上。这是因为 Scala 的集合类型是基于泛型和协变的实现的,而不是直接在类型参数上体现。这意味着,尽管 Set[A] 不是 Set[B] 的子类型,但是可以通过类型转换实现这种关系。

这种设计选择的原因是为了保持类型安全和避免意外的类型转换。如果直接在类型参数上体现协变关系,那么可能会导致类型安全问题,因为可能会意外地将一个子类型的集合赋值给一个父类型的集合。这种情况可能会导致运行时错误或不正确的行为。

因此,尽管不可变集合的类型参数不直接体现协变关系,但是在实际使用中,可以通过类型转换实现协变关系。例如,可以将一个 Set[A] 转换为一个 Set[B],只要 AB 的子类型。这种转换可以通过 asInstanceOf 方法或者 Set.map 方法实现。

总之,Scala 的不可变集合不直接在类型参数上体现协变关系,而是通过类型转换实现。这种设计选择旨在保持类型安全和避免意外的类型转换。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

、逆与不变

Scala 类型参数前添加 + 代表参数化类型在该类型参数上,添加 - 则代表逆,什么都不加就是不变。...,就是函数类型在其返回值类型在其参数类型上逆。...而 get 方法类型显然是 () => T。所以从单元获取元素这个操作上来看,数组在其元素类型。...所以从给数组单元赋值这个操作上看,数组又在其元素类型上逆。因此,数组在其元素类型上不变。 为什么可以写 val person: Person = new Student 呢?...在 Scala ,如果进行了或者逆标记,编译器就会对这个类型参数使用进行检查,如果它出现在了错误位置上,编译器就会提示错误,防止了开发者因此而犯错。

1.9K30

关于 java set,get方法,而为什么推荐直接使用public

set,get....举一个简单例子,如果只是简单赋值操作,直接public 和 set get并无两样,但是如果里面有一些逻辑,比如限制数据大小,这样直接Public 就没办法控制了。...这里引入其中一句话: 在任何相互关系,具有关系所涉及各方都遵守边界是十分重要事情,当创建一个类库时,就建立了与客户端程序员之间关系,他们同样也是程序员,但是他们是使用你类库来构建应用...如果所有的类成员对任何人都是可用,那么客户端程序员就可以对类做任何事情,而不受约束。即使你希望客户端程序员不要直接操作你某些成员,但是如果没有任何访问控制,将无法阻止此事发生。...补充说明,set字面意思设置,get获取,我们了解一下java面向对象编程封闭性与安全性,private 修饰set get方法将方法封闭在了一个特定类,其他类就无法对其变量进行方法,这样就提高了数据安全性

1.5K20
  • Scala教程之:深入理解和逆

    在之前文章我们简单介绍过scala和逆,我们使用+ 来表示类型;使用-表示逆类型;非转化类型不需要添加标记。...假如我们定义一个class C[+A] {} ,这里A类型参数是,这就意味着在方法需要参数是C[AnyRef]时候,我们可以是用C[String]来代替。...函数参数和返回值 现在我们讨论scala函数参数一个非常重要结论:函数参数必须是逆,而返回值必须是 为什么呢?...如果函数参数使用了,返回值使用了逆则会编译失败: scala> trait MyFunction2[+T1, +T2, -R] { | def apply(v1:T1, v2:T2): R =...假如可变参数是ContainerPlus[+A],那么对于: val cp: ContainerPlus[C]=new ContainerPlus(new CSub) 定义类型是C,但是运行时类型

    87730

    Scala学习笔记

    ,定义变量可以指定类型,因为Scala会进行类型自动推导     *)scala条件表达式         IF 判断来说有三种结构:             -1, IF             ...类型而言,具体业务具体对待(看存储数据)             -2:分为可变和不可变                 在Java中所有的集合(List、Map、Set)都是可变                 ...        (1)scala和逆是非常特色功能,完全解决了java泛型一大缺憾             //举例来说:             Java,如果有Bird类是Animal...答案是:不行,因此对于开发程序造成了很多麻烦             //在scala,只要灵活使用和逆,就可以解决Java泛型问题             1:概念:(泛型变量值可以是本身或者其子类类型...)scala类或者特征泛型定义,如果在类型参数前面加入+符号,就可以使类或者特征变成变了                 参考CovarianceDamo代码             2:逆概念

    2.6K40

    编写高质量代码改善C#程序157个建议

    本文主要学习记录以下内容:   建议42、使用泛型参数兼容泛型接口可变性   建议43、让接口中泛型参数支持   建议44、理解委托   建议45、为泛型类型参数指定 建议42、...使用泛型参数兼容泛型接口可变性 让返回值类型返回比声明类型派生程度更大类型,就是“”。...实际上,只要泛型类型参数在一个接口声明不被用来作为方法输入参数,我们都可姑且把它堪称是“返回值”类型。所以,本建议这种模式是满足“定义。...在我们自己代码,如果要编写泛型接口,除非确定该接口中泛型参数涉及变体,否则都建议加上out关键字。增大了接口使用范围,而且几乎不会带来什么副作用。...建议44、理解委托 委托泛型变量天然是部分支持为什么说是“部分支持”呢?

    32930

    学习Scala: 初学者应该了解知识

    implicit conversions逻辑发现类型Int/Long匹配, 然后在一个implicit view(可以看成一个函数pool,包含了所有的implicit functions)找一个输入为...: implicit conversions (from implicit functions and implicit classes) 当Scala发现类型匹配,或者正在调用一个对象不存在函数时...Unit是Scala一个类型,用于表示一个函数没有返回值。 有点像Javavoid,不过其实返回了'()'。...T <: A: 作用于 function, 约束:T是A子类,也称作upper type bound,这是一个。 一般会和-T合用。...请看不变(Invariant), (Covarinat), 逆(Contravariant) : 一个程序猿进化故事 编译.scala文件到jar文件 scalac -d test.jar D:

    1.1K40

    学好Spark必须要掌握Scala技术点

    里用final修饰变量 val i = 1 //使用var定义变量是可变,在Scala鼓励使用val var s = "hello" //Scala编译器会自动推断变量类型...,那么就意味着该变量引用不可变,该引用内容是不是可变还取决于这个引用指向集合类型 2.3 元组 映射是K/V对偶集合,对偶是元组最简单形式,元组可以装着多个不同类型值,元组是不可变 ?...集合分可变(mutable)和不可变(immutable)两种类型,immutable类型集合初始化后长度和内容都不能改变(注意与val修饰变量进行区别) 2.4.1 Seq/List 在Scala...这种细微差别,体现在类型赋值时,因为java里Class[T]是不支持,所以无法把一个 Class[_ < : A] 赋值给一个 Class[A]。...除了上述介绍语法之外,像、逆、actor也需要大家掌握。

    1.6K50

    Scala语言入门:初学者基础语法指南

    Scala (covariance)和逆(contravariance)是用来描述类型参数在子类型关系行为概念。...和逆是用来指定泛型类型参数类型关系方式,以确保类型安全性。 (Covariance): 表示类型参数在子类型关系具有相同方向。...如果一个泛型类类型参数是,那么子类型关系将保持不变,即父类型可以被替换为子类型。在 Scala ,可以使用 + 符号来表示。...通过和逆,我们可以在 Scala 实现更灵活类型关系,并确保类型安全性。这在处理泛型集合或函数参数时特别有用。...然后,定义了一个类 Cage[+A],它接受一个类型参数 A,并使用符号 + 表示 A 是。Cage 类有一个名为 animal 属性,它类型是 A,也就是动物类型

    32920

    Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、

    其中,Iterable是所有集合trait跟trait。这个结构与Java集合体系非常相似。 Scala集合是分成可变和不可变两类集合,其中可变集合就是说,集合元素可以动态修改。...如果不使用泛型进行统一类型限制,那么在后期程序运行过程,难免出现问题,比如传入了希望类型,导致程序出现问题。在使用类时候,比如创建类对象,将类型参数替换为实际类型,即可。...: Scala和逆是非常有特色,解决了Java泛型一大缺憾。...因此对于发开程序造成了很多麻烦。而Scala,只要灵活使用了和逆,就可以解决Java泛型问题。     ...b、使用某个类型对象,调用某个方法,而这个方法并不存在与该类型。 c、使用某个类型对象,调用某个方法,虽然该类型有这个方法,但是给方法传入参数类型,与方法定义接受参数类型匹配。

    2.9K50

    Scala语言入门:初学者基础语法指南

    Scala (covariance)和逆(contravariance)是用来描述类型参数在子类型关系行为概念。...和逆是用来指定泛型类型参数类型关系方式,以确保类型安全性。 (Covariance): 表示类型参数在子类型关系具有相同方向。...如果一个泛型类类型参数是,那么子类型关系将保持不变,即父类型可以被替换为子类型。在 Scala ,可以使用 + 符号来表示。...通过和逆,我们可以在 Scala 实现更灵活类型关系,并确保类型安全性。这在处理泛型集合或函数参数时特别有用。...然后,定义了一个类 Cage[+A],它接受一个类型参数 A,并使用符号 + 表示 A 是。Cage 类有一个名为 animal 属性,它类型是 A,也就是动物类型

    35420

    Scala语言入门:初学者基础语法指南

    Scala (covariance)和逆(contravariance)是用来描述类型参数在子类型关系行为概念。...和逆是用来指定泛型类型参数类型关系方式,以确保类型安全性。 (Covariance): 表示类型参数在子类型关系具有相同方向。...如果一个泛型类类型参数是,那么子类型关系将保持不变,即父类型可以被替换为子类型。在 Scala ,可以使用 + 符号来表示。...通过和逆,我们可以在 Scala 实现更灵活类型关系,并确保类型安全性。这在处理泛型集合或函数参数时特别有用。...然后,定义了一个类 Cage[+A],它接受一个类型参数 A,并使用符号 + 表示 A 是。Cage 类有一个名为 animal 属性,它类型是 A,也就是动物类型

    63210

    Scala语言入门:初学者基础语法指南

    型变在 Scala (covariance)和逆(contravariance)是用来描述类型参数在子类型关系行为概念。...和逆是用来指定泛型类型参数类型关系方式,以确保类型安全性。(Covariance): 表示类型参数在子类型关系具有相同方向。...如果一个泛型类类型参数是,那么子类型关系将保持不变,即父类型可以被替换为子类型。在 Scala ,可以使用 + 符号来表示。...通过和逆,我们可以在 Scala 实现更灵活类型关系,并确保类型安全性。这在处理泛型集合或函数参数时特别有用。...然后,定义了一个类 Cage[+A],它接受一个类型参数 A,并使用符号 + 表示 A 是。Cage 类有一个名为 animal 属性,它类型是 A,也就是动物类型

    35720

    scala快速入门系列【泛型】

    我们在学习集合时候,一般都会涉及到泛型。 ? 那如何自己定义泛型呢? 定义一个泛型方法 在scala,使用方括号来定义类型参数。 语法 ?...定义一个泛型类,直接在类名后面加上方括号,指定要使用泛型参数 指定类对应泛型参数后,就使用这些类型参数来定义变量了 示例 实现一个Pair泛型类 Pair类包含两个字段,而且两个字段类型固定 创建不同类型泛型类对象...} } 、逆、非 spark源代码中大量使用到了、逆、非,学习该知识点对我们将来阅读spark源代码很有帮助。...默认泛型类是非 类型B是A类型,Pair[A]和Pair[B]没有任何从属关系 Java是一样 ? ---- 语法 ?...类型B是A类型,Pair[A]反过来可以认为是Pair[B]类型 参数化类型方向和类型方向是相反 示例 定义一个Super类、以及一个Sub类继承自Super类 使用、逆、非分别定义三个泛型类

    71430

    泛型泛型知多少

    泛型和协 有关协和逆详细说明可以参考:我之前一篇文章:深入理解和逆 http://www.flydean.com/scala-covariance-contravariant/ 这里我再总结一下...,和逆只有在类型声明类型参数里才有意义,对参数化方法没有意义,因为该标记影响是子类继承行为,而方法没有子类。...当然java没有显示表示参数类型还是逆意思是如果有两个类 A 和 A, 其中C是T子类,那么我们可以用A来替代A。 逆就是相反关系。...接下来我们考虑泛型情况,List 是不是 List父类呢?很遗憾,并不是。 我们得出这样一个结论:泛型不是为什么呢?...直接clone T是没有办法了,如果我们想copy一个Setset类型是未定义该怎么做呢? public void useTSet(Set set){ Set<?

    1.1K10

    scala 类型 最详细解释

    >: String] (buf : ListBuffer[T]) = { buf.append( "hi") } 数组类型 : A 是 B 类型, List...[A] 也是 List[B] 类型 : A 是 B 类型, List[B] 是 List[A] 类型 在java引用类型数组类型是支持, 即 String[] 类型是 Object...[] 类型, 比如排序算法: void sort(Object[] a, Comparator cmp) { … } 数组被用来确保任意参数类型数组都可以传入排序方法。...随着java引入了泛型,sort方法可以用类型参数,因此数组不再有用。只是考虑到兼容性。 scala里不支持数组,以尝试保持比java更高纯粹性。...,但在类型上两者是统一;而scala里修正这一点,Int类型不再区分int/Integer,类型一致,所以值为nullInteger在通过asInstanceOf[Int]时被当作一个未初始化Int

    86710

    2021年大数据常用语言Scala(三十六):scala高级用法 泛型

    :List[String] = List("1", "2", "3") list1: List[String] = List(1, 2, 3) 在scala,使用方括号来定义类型参数。...Pair类包含两个值,而且两个值类型固定。...上述T、S都是类型参数,就代表一个类型 指定了类对应类型参数后,就可以使用这些类型参数来定义变量了 上下界 现在,有一个需求,在Pair类,我们只想用来保存Person类型对象,因为我们要添加一个方法...} } U >: T 表示U必须是类型T父类或本身 S <: T 表示S必须是类型T子类或本身 、逆、非  父类对象 可以指向 子类实例,这是多态 如果是泛型之间呢?... class Pair[+T],这种情况是类型B是A类型,Pair[B]可以认为是Pair[A]类型。这种情况,参数化类型方向和类型方向是一致

    75620
    领券