加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

为什么Scala函数在参数不符合类型约束时编译?

发布时间:2020-12-16 09:21:27 所属栏目:安全 来源:网络整理
导读:假设我有一个名为Marker的空标记特征,以及一些带有Marker绑定的类型参数的函数: trait Markerobject Marker { def works[M : Marker](m:M):M = m def doesntWork[M : Marker](f:M = String):String = "doesn't matter"} 第一个功能正如我所料.也就是说,如果
假设我有一个名为Marker的空标记特征,以及一些带有Marker绑定的类型参数的函数:

trait Marker

object Marker {
  def works[M <: Marker](m:M):M = m
  def doesntWork[M <: Marker](f:M => String):String = "doesn't matter"
}

第一个功能正如我所料.也就是说,如果传递的参数不是Marker,那么代码不会编译:

scala> works("a string")
<console>:14: error: inferred type arguments [String] do not conform to method works's type parameter bounds [M <: com.joescii.Marker]
       works("a string")
       ^
<console>:14: error: type mismatch;
 found   : String("a string")
 required: M
       works("a string")
             ^

但是,我能够将参数传递给不符合Marker的第二个函数.具体来说,我可以传递一个String =>字符串和代码愉快地编译和运行:

scala> doesntWork( (str:String) => "a string" )
res1: String = doesn't matter

我希望这个调用doesntWork无法编译.任何人都可以向我解释为什么编译,以及如何更改功能签名,以防止类型检查在这种情况下?

全面披露:上述设计的例子是this outstanding issue for lift-ng的简化版本.

解决方法

M => String实际上是一个Function1 [M,String].如果你看这个定义:

trait Function1[-T1,+R]

所以M变为逆变,这意味着对于M1>:M2,Function1 [M1,String]<:Function1 [M2,String],假设M1 = Any then Function1 [Any,String]<:Function1 [Marker,串]. 而输入的dontWork-f也是相反的,这意味着你可以传递比M => String,正如我刚刚显示的,Any =>字符串小于Marker =>字符串,所以它的passess完全正常.

你也可以传递String =>字符串,因为你的[M <= Marker],这最终导致编译器将M解释为Nothing,所以即使String =>字符串变得大于M =>串.

为了解决你的问题,只需要介绍wrapper,这将使你的类型不变:

scala> case class F[M](f: M => String)
defined class F

scala> def doesntWork[M <: Marker](f:F[M]):String = "doesn't matter"
doesntWork: [M <: Marker](f: F[M])String

scala> doesntWork(F((str: String) => "a string"))
<console>:18: error: inferred type arguments [String] do not conform to method doesntWork's type parameter bounds [M <: Marker]
              doesntWork(F((str: String) => "a string"))
              ^
<console>:18: error: type mismatch;
 found   : F[String]
 required: F[M]
              doesntWork(F((str: String) => "a string"))
                          ^
scala> doesntWork(F((str: Any) => "a string"))
<console>:18: error: inferred type arguments [Any] do not conform to method doesntWork's type parameter bounds [M <: Marker]
              doesntWork(F((str: Any) => "a string"))
              ^
<console>:18: error: type mismatch;
 found   : F[Any]
 required: F[M]
Note: Any >: M,but class F is invariant in type M.
You may wish to define M as -M instead. (SLS 4.5)
              doesntWork(F((str: Any) => "a string"))

scala> doesntWork(F((str: Marker) => "a string"))
res21: String = doesn't matter

scala> trait Marker2 extends Marker
defined trait Marker2

scala> doesntWork(F((str: Marker) => "a string"))
res22: String = doesn't matter

scala> doesntWork(F((str: Marker2) => "a string"))
res23: String = doesn't matter

推荐这样的隐式转换通常是不好的,但在这里似乎很好(如果你不会过度使用F):

scala> implicit def wrap[M](f: M => String) = F(f)
warning: there was one feature warning; re-run with -feature for details
wrap: [M](f: M => String)F[M]

scala> doesntWork((str: Marker) => "a string")
res27: String = doesn't matter

scala> doesntWork((str: String) => "a string")
<console>:21: error: inferred type arguments [String] do not conform to method doesntWork's type parameter bounds [M <: Marker]
              doesntWork((str: String) => "a string")
              ^
<console>:21: error: type mismatch;
 found   : F[String]
 required: F[M]
              doesntWork((str: String) => "a string")
                                       ^

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读