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

解密最棘手的scala方法原型之一(光滑)

发布时间:2020-12-16 19:02:03 所属栏目:安全 来源:网络整理
导读:看着方法在下面的 scala slick类中,从 http://slick.typesafe.com/doc/2.1.0/api/index.html#scala.slick.lifted.ToShapedValue开始,它让我想起了 that iconic stackoverflow thread about scala prototypes. def [R,U](f: (U) ? R,g: (R) ? Option[U])(impl
看着<>方法在下面的 scala slick类中,从 http://slick.typesafe.com/doc/2.1.0/api/index.html#scala.slick.lifted.ToShapedValue开始,它让我想起了 that iconic stackoverflow thread about scala prototypes.

def <>[R,U](f: (U) ? R,g: (R) ? Option[U])
(implicit arg0: ClassTag[R],shape: Shape[_ <: FlatShapeLevel,T,U,_]):
MappedProjection[R,U]

有人大胆且知识渊博,可以提供这个长原型定义的明确演练,仔细澄清所有类型的协方差/不变性,双参数列表和其他高级scala方面吗?

这个练习也将极大地帮助处理类似复杂的原型!

解决方法

好的,我们来看看:

class ToShapedValue[T](val value: T) extends AnyVal {
  ...
  @inline def <>[R: ClassTag,g: (R) ? Option[U])(implicit shape: Shape[_ <: FlatShapeLevel,_]): MappedProjection[R,U]
}

该类是AnyVal包装器;虽然我实际上看不到从快速查看隐式转换,它闻起来像“皮条客我的图书馆”模式.所以我猜这是为了添加<>作为某些(或可能是所有)类型的“扩展方法”.

@inline是一种注释,一种将元数据放在任何东西上的方法;这个是对编译器的暗示,应该内联. <>是方法名称 – 很多看起来像“运算符”的东西只是scala中的普通方法.

您链接的文档已经将R:ClassTag扩展为普通R和隐式ClassTag [R] – 这是一个“上下文绑定”,它只是语法糖. ClassTag是一个编译器生成的东西,它存在于每个(具体)类型并有助于反射,所以这是一个提示,该方法可能会在某些时候对R做一些反思.

现在,肉:这是一个通用方法,由两种类型参数化:[R,U].它的论点是两个函数,f:U => R和g:R =>选项[U].这看起来有点像功能性的Prism概念 – 从U到R的转换始终有效,从R到U的转换有时不起作用.

签名(有点)的有趣部分是最后的隐式形状. Shape被描述为“类型类”,所以这可能最好被认为是一个“约束”:它限制了我们可以用这个函数调用的可能类型U和R,只限于那些适当的Shape可用的类型.

看看the documentation forShape,我们看到四种类型是Level,Mixed,Unpacked和Packed.所以约束是:必须有一个Shape,其“level”是FlatShapeLevel的某个子类型,其中Mixed类型为T,Unpacked类型为R(Packed类型可以是任何类型).

所以,这是一个类型级函数,表示R是“T的解压缩版本”.再次使用Shape文档中的示例,如果T是(Column [Int],Column [(Int,String)],(Int,Option [Double]))然后R将是(Int,String),Option [Double])(它只适用于FlatShapeLevel,但我会做一个判断调用,那是可能并不重要.)有趣的是,U完全不受约束.

因此,我们可以通过在两个方向上提供转换函数,从任何T创建MappedProjection [unpacked-version-of-T,U].因此,在简单版本中,T可能是Column [String] – 数据库中String列的表示 – 我们希望将其表示为某些特定于应用程序的类型,例如电子邮件地址.所以R = String,U = EmailAddress,我们在两个方向提供转换函数:f:EmailAddress => String和g:String =>选项[EmailAddress的].这是有意义的:它是这样的:每个EmailAddress都可以表示为一个字符串(至少,如果我们希望能够将它们存储在数据库中,它们最好是这样),但不是每个String都是有效的EmailAddress.如果我们的数据库以某种方式有电子邮件地址栏中的“http://www.foo.com/”,我们的g将返回None,而Slick可以优雅地处理此问题.

遗憾的是,MappedProjection本身没有记录.但我猜它是我们可以查询的东西的某种懒惰表示;我们有一个Column [String],现在我们有一个伪列的东西,其(底层)类型是EmailAddress.所以这可能允许我们编写伪查询,比如’select from users where emailAddress.domain =“gmail.com”’,这是不可能直接在数据库中做的(不知道电子邮件地址的哪一部分是域名),但很容易在代码的帮助下完成.至少,这是我对它可能做的最好的猜测.

可以说,通过使用标准Prism类型(例如来自Monocle的类型)而不是明确地传递一对函数,可以使函数更清晰.使用隐式提供类型级函数是笨拙但必要的;在一个完全依赖类型的语言(例如Idris)中,我们可以将我们的类型级函数编写为函数(类似于def unpackedType(t:Type):Type = …).从概念上讲,这个函数看起来像:

def <>[U](p: Prism[U,unpackedType(T)]): MappedProjection[unpackedType(T),U]

希望这能解释一些阅读新的,不熟悉的功能的思考过程.我根本不知道Slick,所以我不知道我对这个<>的准确程度.用于 – 我做对了吗?

(编辑:李大同)

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

    推荐文章
      热点阅读