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

使用Scala隐式的类型平等

发布时间:2020-12-16 18:59:06 所属栏目:安全 来源:网络整理
导读:我一直在阅读一些 Scala类型编程的东西.主要是Apocalisp博客,也是Alexander Lehmann的YouTube谈话. 我有点困惑我猜这可能是非常基本的,这是使用隐含的比较两种类型,如下所示: implicitly[Int =:= Int] Apocalisp博客上的标记说: This is useful for captur
我一直在阅读一些 Scala类型编程的东西.主要是Apocalisp博客,也是Alexander Lehmann的YouTube谈话.

我有点困惑我猜这可能是非常基本的,这是使用隐含的比较两种类型,如下所示:

implicitly[Int =:= Int]

Apocalisp博客上的标记说:

This is useful for capturing an implicit value that is in scope and has type T.

我得到如何使这项工作,但我不知道为什么它的工作,所以不想继续前进.

在上面的例子中有一个隐含的类型“Int”在范围内,“隐含地”从以太网中获取,允许代码编译?如何与’function1’返回类型相符?

res0: =:=[Int,Int] = <function1>

此外,这隐含于哪里?在我的特质“Foo”的情况下,为什么呢?

implicitly[Foo =:= Foo]

编译?在这种情况下,“Foo”隐含在哪里?

如果这是一个非常愚蠢的问题,提前道歉,谢谢任何帮助!

解决方法

X =:= Y只是类型= = = [X,Y]的句法糖(中缀符号).

所以当你隐含地[Y =:= Y]时,你只需要查找一个类型为= = = [X,Y]的隐式值.
=:=是Predef中定义的一般特征.

另外,=:=是一个有效的类型名称,因为类型名称(就像任何标识符)可以包含特殊字符.

从现在开始,我们将= = =重新命名为IsSameType,并删除中缀符号,以使我们的代码更加清晰直观.
这给了我们隐含的[IsSameType [X,Y]]

以下是这种类型定义的简化版本:

sealed abstract class IsSameType[X,Y]
object IsSameType {
   implicit def tpEquals[A] = new IsSameType[A,A]{}
}

注意tpEquals如何为任何类型A提供IsSameType [A,A]的隐式值.
换句话说,当且仅当X和Y是相同类型时,它才会提供IsSameType [X,Y]的隐含值.
所以隐含的[IsSameType [Foo,Foo]]编译好.
但是隐含地[IsSameType [Int,String]]不存在,因为在这里,tpEquals是不适用的,因为IsSameType [Int,String]类型的范围内没有隐含的内容.

所以使用这个非常简单的结构,我们可以静态地检查一些类型X与另一个类型Y相同.

现在这里是一个如何有用的例子.说我想定义一个Pair类型(忽略它已经存在于标准库中的事实):

case class Pair[X,Y]( x: X,y: Y ) {
  def swap: Pair[Y,X] = Pair( y,x )
}

Pair参数化与其2个元素的类型,这可以是任何东西,最重要的是不相关.
现在,如果我想定义一个将该对转换为2个元素列表的方法toList?
这种方法在X和Y相同的情况下才会有意义,否则我将被迫返回List [Any].
我当然不想改变Pair对Pair(T:y,T)的定义,因为我真的希望能够有异构类型的对.
毕竟,只有在调用toList时才需要这个X == Y.所有其他方法(如swap)都应该被调用在任何种类的异构对上.
所以最后我真的想静态地确保X == Y,但是只有在调用toList的时候,在这种情况下,返回一个List [X](或者一个List [Y],这是一样的事情变得可能和一致):

case class Pair[X,x )
  def toList( implicit evidence: IsSameType[X,Y] ): List[Y] = ???
}

但是实际上实现toList还是一个严重的问题.如果我尝试编写明显的实现,则无法编译:

def toList( implicit evidence: IsSameType[X,Y] ): List[Y] = List[Y]( x,y )

编译器会抱怨x不是Y类型.实际上,就编译器来说,X和Y仍然是不同的类型.
只有仔细的施工,我们可以静静地确定X == Y
(即,toList采用IsSameType [X,Y]类型的隐式值,只有当X == Y时,它们由方法tpEquals提供).
但是编译器肯定不会破译这个精明的结构来得出结论:X == Y.

如果我们知道X == Y(或换句话说,我们在范围内有一个IsSameType [X,Y]的一个实例),我们可以做的是提供从X到Y的隐式转换.

// A simple cast will do,given that we statically know that X == Y
implicit def sameTypeConvert[X,Y]( x: X )( implicit evidence: IsSameType[X,Y] ): Y = x.asInstanceOf[Y]

现在,我们对toList的实现最终编译成精细:x将通过隐式转换sameTypeConvert简单地转换为Y.

作为最后的调整,我们可以进一步简化事情:鉴于我们已经将隐含的价值(证据)作为参数,
为什么没有这个值实现转换?喜欢这个:

sealed abstract class IsSameType[X,Y] extends (X => Y) {
  def apply( x: X ): Y = x.asInstanceOf[Y]
}
object IsSameType {
   implicit def tpEquals[A] = new IsSameType[A,A]{}
}

然后,我们可以删除sameTypeConvert方法,因为IsSameType实例本身现在提供了隐式转换.
现在IsSameType具有双重目的:静态地确保X == Y和(如果是),提供实际允许我们将X的实例视为Y的实例的隐式转换.

我们现在基本上重新实现了Predef中定义的类型=:=

(编辑:李大同)

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

    推荐文章
      热点阅读