强制类型差异

强制类型差异

在Scala中,我可以在编译时强制类型相等。例如:

case class Foo[A,B]( a: A, b: B )( implicit ev: A =:= B )scala> Foo( 1, 2 )res3: Foo[Int,Int] = Foo(1,2)scala> Foo( 1, "2" )<console>:10: error: Cannot prove that Int =:= java.lang.String.

是否有办法强制执行A型和B型应该不同的做法?


MM们
浏览 228回答 3
3回答

PIPIONE

借用让-菲利普的想法,这是有效的:sealed&nbsp;class&nbsp;=!=[A,B]trait&nbsp;LowerPriorityImplicits&nbsp;{ &nbsp;&nbsp;implicit&nbsp;def&nbsp;equal[A]:&nbsp;=!=[A,&nbsp;A]&nbsp;=&nbsp;sys.error("should&nbsp;not&nbsp;be&nbsp;called")}object&nbsp;=!=&nbsp;extends&nbsp;LowerPriorityImplicits&nbsp;{ &nbsp;&nbsp;implicit&nbsp;def&nbsp;nequal[A,B](implicit&nbsp;same:&nbsp;A&nbsp;=:=&nbsp;B&nbsp;=&nbsp;null):&nbsp;=!=[A,B]&nbsp;=&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(same&nbsp;!=&nbsp;null)&nbsp;sys.error("should&nbsp;not&nbsp;be&nbsp;called&nbsp;explicitly&nbsp;with&nbsp;same&nbsp;type") &nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;new&nbsp;=!=[A,B]}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;class&nbsp;Foo[A,B](a:&nbsp;A,&nbsp;b:&nbsp;B)(implicit&nbsp;e:&nbsp;A&nbsp;=!=&nbsp;B)然后://&nbsp;compiles:Foo(1f,&nbsp;1.0)Foo("",&nbsp;1.0)Foo("",&nbsp;1)Foo("Fish",&nbsp;Some("Fish"))//&nbsp;doesn't&nbsp;compile//&nbsp;Foo(1f,&nbsp;1f)//&nbsp;Foo("",&nbsp;"")我可能会简化如下,因为对“作弊”的检查总是可以避免的。Foo(1, 1)(null)或=!=.nequal(null)):sealed&nbsp;class&nbsp;=!=[A,B]trait&nbsp;LowerPriorityImplicits&nbsp;{ &nbsp;&nbsp;/**&nbsp;do&nbsp;not&nbsp;call&nbsp;explicitly!&nbsp;*/ &nbsp;&nbsp;implicit&nbsp;def&nbsp;equal[A]:&nbsp;=!=[A,&nbsp;A]&nbsp;=&nbsp;sys.error("should&nbsp;not&nbsp;be&nbsp;called")}object&nbsp;=!=&nbsp;extends&nbsp;LowerPriorityImplicits&nbsp;{ &nbsp;&nbsp;/**&nbsp;do&nbsp;not&nbsp;call&nbsp;explicitly!&nbsp;*/ &nbsp;&nbsp;implicit&nbsp;def&nbsp;nequal[A,B]:&nbsp;=!=[A,B]&nbsp;=&nbsp;new&nbsp;=!=[A,B]}

qq_花开花谢_0

我有一个更简单的解决方案,它也利用了模糊性,trait&nbsp;=!=[A,&nbsp;B]implicit&nbsp;def&nbsp;neq[A,&nbsp;B]&nbsp;:&nbsp;A&nbsp;=!=&nbsp;B&nbsp;=&nbsp;null//&nbsp;This&nbsp;pair&nbsp;excludes&nbsp;the&nbsp;A&nbsp;=:=&nbsp;B&nbsp;caseimplicit&nbsp;def&nbsp;neqAmbig1[A]&nbsp;:&nbsp;A&nbsp;=!=&nbsp;A&nbsp;=&nbsp;nullimplicit&nbsp;def&nbsp;neqAmbig2[A]&nbsp;:&nbsp;A&nbsp;=!=&nbsp;A&nbsp;=&nbsp;null最初的用例,case&nbsp;class&nbsp;Foo[A,B](a&nbsp;:&nbsp;A,&nbsp;b&nbsp;:&nbsp;B)(implicit&nbsp;ev:&nbsp;A&nbsp;=!=&nbsp;B)new&nbsp;Foo(1,&nbsp;"1")new&nbsp;Foo("foo",&nbsp;Some("foo"))//&nbsp;These&nbsp;don't&nbsp;compile//&nbsp;new&nbsp;Foo(1,&nbsp;1)//&nbsp;new&nbsp;Foo("foo",&nbsp;"foo")//&nbsp;new&nbsp;Foo(Some("foo"),&nbsp;Some("foo"))更新我们可以把这个和我的“神奇的打字技巧”(谢谢@JPP;-)如下:type&nbsp;¬[T]&nbsp;=&nbsp;T&nbsp;=>&nbsp;Nothingimplicit&nbsp;def&nbsp;neg[T,&nbsp;U](t&nbsp;:&nbsp;T)(implicit&nbsp;ev&nbsp;:&nbsp;T&nbsp;=!=&nbsp;U)&nbsp;:&nbsp;¬[U]&nbsp;=&nbsp;nulldef&nbsp;notString[T&nbsp;<%&nbsp;¬[String]](t&nbsp;:&nbsp;T)&nbsp;=&nbsp;tREPL样本会话,scala>&nbsp;val&nbsp;ns1&nbsp;=&nbsp;notString(1)ns1:&nbsp;Int&nbsp;=&nbsp;1scala>&nbsp;val&nbsp;ns2&nbsp;=&nbsp;notString(1.0)ns2:&nbsp;Double&nbsp;=&nbsp;1.0scala>&nbsp;val&nbsp;ns3&nbsp;=&nbsp;notString(Some("foo"))ns3:&nbsp;Some[java.lang.String]&nbsp;=&nbsp;Some(foo)scala>&nbsp;val&nbsp;ns4&nbsp;=&nbsp;notString("foo")<console>:14:&nbsp;error:&nbsp;No&nbsp;implicit&nbsp;view&nbsp;available&nbsp;from&nbsp; &nbsp;&nbsp;java.lang.String&nbsp;=>&nbsp;(String)&nbsp;=>&nbsp;Nothing. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val&nbsp;ns4&nbsp;=&nbsp;notString2("foo") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^

慕的地10843

我喜欢Miles Sabin的第一个解决方案的简单性和有效性,但对我们得到的错误没有多大帮助这一事实有点不满意:例如,定义如下:def&nbsp;f[T](&nbsp;implicit&nbsp;e:&nbsp;T&nbsp;=!=&nbsp;String&nbsp;)&nbsp;{}调度要做f[String]将无法编译:<console>:10:&nbsp;error:&nbsp;ambiguous&nbsp;implicit&nbsp;values: &nbsp;both&nbsp;method&nbsp;neqAmbig1&nbsp;in&nbsp;object&nbsp;=!=&nbsp;of&nbsp;type&nbsp;[A]=>&nbsp;=!=[A,A] &nbsp;and&nbsp;method&nbsp;neqAmbig2&nbsp;in&nbsp;object&nbsp;=!=&nbsp;of&nbsp;type&nbsp;[A]=>&nbsp;=!=[A,A] &nbsp;match&nbsp;expected&nbsp;type&nbsp;=!=[String,String] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[String] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^我宁愿让编译器告诉我“T和字符串没有什么不同”,结果发现,如果添加另一个层次的派生,那么我们就可以将歧义错误为隐未发现错误。从那时起,我们可以使用implicitNotFound发出自定义错误消息的注释:@annotation.implicitNotFound(msg&nbsp;=&nbsp;"Cannot&nbsp;prove&nbsp;that&nbsp;${A}&nbsp;=!=&nbsp;${B}.")trait&nbsp;=!=[A,B]object&nbsp;=!=&nbsp;{ &nbsp;&nbsp;class&nbsp;Impl[A,&nbsp;B] &nbsp;&nbsp;object&nbsp;Impl&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;neq[A,&nbsp;B]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;=&nbsp;null &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;neqAmbig1[A]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;A&nbsp;=&nbsp;null &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;neqAmbig2[A]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;A&nbsp;=&nbsp;null &nbsp;&nbsp;} &nbsp;&nbsp;implicit&nbsp;def&nbsp;foo[A,B](&nbsp;implicit&nbsp;e:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;):&nbsp;A&nbsp;=!=&nbsp;B&nbsp;=&nbsp;null}现在让我们试着打电话f[String]:scala>&nbsp;f[String]<console>:10:&nbsp;error:&nbsp;Cannot&nbsp;prove&nbsp;that&nbsp;String&nbsp;=!=&nbsp;String. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[String] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^那好多了。谢谢编译器。对于那些喜欢上下文绑定语法糖的人来说,最后一个技巧是可以定义这个别名(基于lambdas类型):type&nbsp;IsNot[A]&nbsp;=&nbsp;{&nbsp;type&nbsp;λ[B]&nbsp;=&nbsp;A&nbsp;=!=&nbsp;B&nbsp;}然后我们就可以定义f就像这样:def&nbsp;f[T:IsNot[String]#λ]&nbsp;{}它是否容易阅读是高度主观的。在任何情况下,都比写入完整的隐式参数列表短得多。更新*为了完整性,这里有一个等价的代码来表示A的子类型B:@annotation.implicitNotFound(msg&nbsp;=&nbsp;"Cannot&nbsp;prove&nbsp;that&nbsp;${A}&nbsp;<:!<&nbsp;${B}.")trait&nbsp;<:!<[A,B]object&nbsp;<:!<&nbsp;{ &nbsp;&nbsp;class&nbsp;Impl[A,&nbsp;B] &nbsp;&nbsp;object&nbsp;Impl&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;nsub[A,&nbsp;B]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;=&nbsp;null &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;nsubAmbig1[A,&nbsp;B>:A]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;=&nbsp;null &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;nsubAmbig2[A,&nbsp;B>:A]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;=&nbsp;null &nbsp;&nbsp;} &nbsp;&nbsp;implicit&nbsp;def&nbsp;foo[A,B](&nbsp;implicit&nbsp;e:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;):&nbsp;A&nbsp;<:!<&nbsp;B&nbsp;=&nbsp;null}type&nbsp;IsNotSub[B]&nbsp;=&nbsp;{&nbsp;type&nbsp;λ[A]&nbsp;=&nbsp;A&nbsp;<:!<&nbsp;B&nbsp;}并表达了A不可兑换为B&nbsp;:@annotation.implicitNotFound(msg&nbsp;=&nbsp;"Cannot&nbsp;prove&nbsp;that&nbsp;${A}&nbsp;<%!<&nbsp;${B}.")trait&nbsp;<%!<[A,B]object&nbsp;<%!<&nbsp;{ &nbsp;&nbsp;class&nbsp;Impl[A,&nbsp;B] &nbsp;&nbsp;object&nbsp;Impl&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;nconv[A,&nbsp;B]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;=&nbsp;null &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;nconvAmbig1[A<%B,&nbsp;B]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;=&nbsp;null &nbsp;&nbsp;&nbsp;&nbsp;implicit&nbsp;def&nbsp;nconvAmbig2[A<%B,&nbsp;B]&nbsp;:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;=&nbsp;null &nbsp;&nbsp;} &nbsp;&nbsp;implicit&nbsp;def&nbsp;foo[A,B](&nbsp;implicit&nbsp;e:&nbsp;A&nbsp;Impl&nbsp;B&nbsp;):&nbsp;A&nbsp;<%!<&nbsp;B&nbsp;=&nbsp;null}type&nbsp;IsNotView[B]&nbsp;=&nbsp;{&nbsp;type&nbsp;λ[A]&nbsp;=&nbsp;A&nbsp;<%!<&nbsp;B&nbsp;}
打开App,查看更多内容
随时随地看视频慕课网APP