[SCALA] 유형의 차이를 적용
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 형을 집행 할 수있는 방법이 있습니까?
해결법
-
==============================
1.이 작동 장 - 필립의 아이디어 떨어져 Riffing :
이 작동 장 - 필립의 아이디어 떨어져 Riffing :
sealed class =!=[A,B] trait LowerPriorityImplicits { implicit def equal[A]: =!=[A, A] = sys.error("should not be called") } object =!= extends LowerPriorityImplicits { implicit def nequal[A,B](implicit same: A =:= B = null): =!=[A,B] = if (same != null) sys.error("should not be called explicitly with same type") else new =!=[A,B] } case class Foo[A,B](a: A, b: B)(implicit e: A =!= B)
그때:
// compiles: Foo(1f, 1.0) Foo("", 1.0) Foo("", 1) Foo("Fish", Some("Fish")) // doesn't compile // Foo(1f, 1f) // Foo("", "")
다음과 같이 아마,이 단순화 것 항상 어쨌든 피할 수있다 "속이고"에 대한 검사하기 때문에 (예를 들어, 푸 (1, 1) (널) 또는 = nequal (NULL)!.)
sealed class =!=[A,B] trait LowerPriorityImplicits { /** do not call explicitly! */ implicit def equal[A]: =!=[A, A] = sys.error("should not be called") } object =!= extends LowerPriorityImplicits { /** do not call explicitly! */ implicit def nequal[A,B]: =!=[A,B] = new =!=[A,B] }
-
==============================
2.나는 또한 모호성을 활용하는 간단한 해결책을 가지고
나는 또한 모호성을 활용하는 간단한 해결책을 가지고
trait =!=[A, B] implicit def neq[A, B] : A =!= B = null // This pair excludes the A =:= B case implicit def neqAmbig1[A] : A =!= A = null implicit def neqAmbig2[A] : A =!= A = null
원래 사용 사례,
case class Foo[A,B](a : A, b : B)(implicit ev: A =!= B) new Foo(1, "1") new Foo("foo", Some("foo")) // These don't compile // new Foo(1, 1) // new Foo("foo", "foo") // new Foo(Some("foo"), Some("foo"))
최신 정보
우리는 감사 @jpp 다음과 ;-)로 (내 "마법의 자료형 체계 속임수"에이 관련 될 수
type ¬[T] = T => Nothing implicit def neg[T, U](t : T)(implicit ev : T =!= U) : ¬[U] = null def notString[T <% ¬[String]](t : T) = t
샘플 REPL 세션,
scala> val ns1 = notString(1) ns1: Int = 1 scala> val ns2 = notString(1.0) ns2: Double = 1.0 scala> val ns3 = notString(Some("foo")) ns3: Some[java.lang.String] = Some(foo) scala> val ns4 = notString("foo") <console>:14: error: No implicit view available from java.lang.String => (String) => Nothing. val ns4 = notString2("foo") ^
-
==============================
3.나는 마일 사빈의 첫 번째 솔루션의 단순성과 효율성을 좋아하지만, 우리가 얻을 오류가 매우 도움이되지는 사실에 약간 불만이었다 :
나는 마일 사빈의 첫 번째 솔루션의 단순성과 효율성을 좋아하지만, 우리가 얻을 오류가 매우 도움이되지는 사실에 약간 불만이었다 :
다음과 같은 정의와 예에 의하여 :
def f[T]( implicit e: T =!= String ) {}
[문자열] f를 수행하려고하면 컴파일에 실패합니다 :
<console>:10: error: ambiguous implicit values: both method neqAmbig1 in object =!= of type [A]=> =!=[A,A] and method neqAmbig2 in object =!= of type [A]=> =!=[A,A] match expected type =!=[String,String] f[String] ^
차라리 컴파일러의 라인을 따라 나에게 무언가를 말할 거라고 "T 것은 문자열 다르지 않다" 그것은 우리가 모호성 오류를 설정하는 방식으로 implicits의 또 다른 레벨을 추가 할 경우 그것은 아주 쉽게 밝혀 암시 찾을 수 없음 오류로. 그때부터 우리는 사용자 지정 오류 메시지를 방출하는 implicitNotFound 주석을 사용할 수 있습니다 :
@annotation.implicitNotFound(msg = "Cannot prove that ${A} =!= ${B}.") trait =!=[A,B] object =!= { class Impl[A, B] object Impl { implicit def neq[A, B] : A Impl B = null implicit def neqAmbig1[A] : A Impl A = null implicit def neqAmbig2[A] : A Impl A = null } implicit def foo[A,B]( implicit e: A Impl B ): A =!= B = null }
이제 F [문자열]을 호출 할 수 있습니다 :
scala> f[String] <console>:10: error: Cannot prove that String =!= String. f[String] ^
그게 낫다. 감사합니다 컴파일러.
문법 설탕 바인딩 컨텍스트를 좋아하는 사람들, 하나는이 별명을 정의 할 수 있습니다위한 마지막 트릭으로 (타입 람다 기준) :
type IsNot[A] = { type λ[B] = A =!= B }
그리고 우리는이 같은 f를 정의 할 수 있습니다 :
def f[T:IsNot[String]#λ] {}
쉽게 읽을 여부는 매우 주관적이다. 어떤 경우에는 전체 암시 적 매개 변수 목록을 작성하는 것보다 확실히 짧습니다.
업데이트 : 완전성 들면임을 표현 여기 해당 코드 B의 서브 타입이다 :
@annotation.implicitNotFound(msg = "Cannot prove that ${A} <:!< ${B}.") trait <:!<[A,B] object <:!< { class Impl[A, B] object Impl { implicit def nsub[A, B] : A Impl B = null implicit def nsubAmbig1[A, B>:A] : A Impl B = null implicit def nsubAmbig2[A, B>:A] : A Impl B = null } implicit def foo[A,B]( implicit e: A Impl B ): A <:!< B = null } type IsNotSub[B] = { type λ[A] = A <:!< B }
그리고하는을 표현하는 B로 변환되지 않습니다 :
@annotation.implicitNotFound(msg = "Cannot prove that ${A} <%!< ${B}.") trait <%!<[A,B] object <%!< { class Impl[A, B] object Impl { implicit def nconv[A, B] : A Impl B = null implicit def nconvAmbig1[A<%B, B] : A Impl B = null implicit def nconvAmbig2[A<%B, B] : A Impl B = null } implicit def foo[A,B]( implicit e: A Impl B ): A <%!< B = null } type IsNotView[B] = { type λ[A] = A <%!< B }
-
==============================
4.Landei의 생각을 바탕으로, 다음은 작동하는 것 같다 :
Landei의 생각을 바탕으로, 다음은 작동하는 것 같다 :
case class Foo[A, B <: A, C <: A]( a: B, b: C)(implicit f: AnyVal <:< A) scala> Foo(1f, 1.0) res75: Foo[AnyVal,Float,Double] = Foo(1.0,1.0) scala> Foo("", 1.0) res76: Foo[Any,java.lang.String,Double] = Foo(,1.0) scala> Foo(1f, 1f) <console>:10: error: Cannot prove that AnyVal <:< Float. Foo(1f, 1f) ^ scala> Foo("", "") <console>:10: error: Cannot prove that AnyVal <:< java.lang.String. Foo("", "") ^ scala> Foo("", 1) res79: Foo[Any,java.lang.String,Int] = Foo(,1)
-
==============================
5.여기에 또 다른 시도이다 :
여기에 또 다른 시도이다 :
class =!=[A, B] private () extends NotNull object =!= { implicit def notMeantToBeCalled1[A, B >: A, C >: B <: A]: =!=[B, A] = error("should not be called") implicit def notMeantToBeCalled2[A, B >: A, C >: B <: A]: =!=[B, A] = error("should not be called") implicit def unambigouslyDifferent[A, B](implicit same: A =:= B = null): =!=[A, B] = if (same != null) error("should not be called explicitly with the same type") else new =!= } case class Foo[A, B](a: A, b: B)(implicit ev: A =!= B)
그런 다음 다시 :
// compiles: Foo(1f, 1.0) Foo("", 1.0) Foo("", 1) Foo("Fish", Some("Fish")) // doesn't compile // Foo(1f, 1f) // Foo("", "")
내 다른 제안에서와 마찬가지로, 여기에 목표는 A와 B가 동일한 경우 컴파일시 모호성을 소개하는 것입니다. 그렇지 않은 경우, A는 B와 동일하고, 암시 모호이고 여기서는 경우 두 implicits을 제공한다.
문제가 여전히 명시 적으로 수동 =! =. notMeantToBeCalled1 또는 =! =. unambigouslyDifferent를 호출하여 암시 적 매개 변수를 제공 할 수 있음을 유의하십시오. 나는 컴파일시에이를 방지 할 수있는 방법을 생각하지 못했습니다. 그러나, 우리는 unambigouslyDifferent는 증거 매개 변수 자체는 A가 B와 동일 여부를 나타내는하지만 잠깐 ... 우리는 정반대을 증명하려고하지 있습니까 요구하는 트릭, 런타임에 예외를 던질 수 있습니까? 같은 암시 적 파라미터가 null의 기본값이 왜 그래, 그입니다. 그리고 우리는 모든 법적 용도에 널 (null)이 될 것으로 예상 - 불쾌한 사용자가 예를 들어, 호출 할 때이 null이 될하지 않을 유일한 시간이다 푸 (1 층, 1 층) (=. = unambiguouslyDifferent [플로트는 플로트), 거기에 우리가 예외를 throw하여 부정 행위를 방지 할 수 있습니다.
-
==============================
6.어떻게 이런 일에 대해, 다음?
어떻게 이런 일에 대해, 다음?
class Foo[A, B] private (a: A, b: B) object Foo { def apply[A, B <: A, C >: A <: B](a: A, b: B)(implicit nothing: Nothing) = nothing def apply[A, B >: A, C >: B <: A](a: A, b: B)(implicit nothing: Nothing, dummy: DummyImplicit) = nothing def apply[A, B](a: A, b: B): Foo[A, B] = new Foo(a, b) }
그때:
// compiles: Foo(1f, 1.0) Foo("", 1.0) Foo("", 1) Foo("Fish", Some("Fish")) // doesn't compile // Foo(1f, 1f) // Foo("", "")
아이디어는 A는 그들이 동일한 B와 동일하고, 모호하지 때 때 해상도가 모호하게하는 것입니다. 더 모호한 방법을 호출 할 수 없습니다 것을 강조하기 위해, 나는 주위 않을 것입니다 (그들은 명시 적으로 삽입하려고하면 확실히 호출자에게 잘못 보일 것입니다) 유형 아무것도의 암시했다. 합니다 (DummyImplicit의 역할은 먼저 두 가지 방법으로 다른 특성을 제공하는 막이다.)
-
==============================
7.이 답변, 답변이 무엇인지 내가 생각할 수있는 단지 시작되지 않습니다. 코드는 아래의 예 또는 [B], AreEqual [A] 암시 적으로 요청하는 경우 종류가 동일인지 여부에 따라서 어떤 하나를 반환하지 않습니다. 어떻게 실제로 내가 알아낼 수 없었다 수표를 만들기 위해 거기에서 이동합니다. 아마 전체 접근 방식은 아마도 누군가가 무언가를 할 수있다, 운명을 정한다. 알았지, 암시 적으로 [없음 [A는 B가] 항상 뭔가를 반환합니다, 하나는 그것을 사용할 수 없습니다. :-(
이 답변, 답변이 무엇인지 내가 생각할 수있는 단지 시작되지 않습니다. 코드는 아래의 예 또는 [B], AreEqual [A] 암시 적으로 요청하는 경우 종류가 동일인지 여부에 따라서 어떤 하나를 반환하지 않습니다. 어떻게 실제로 내가 알아낼 수 없었다 수표를 만들기 위해 거기에서 이동합니다. 아마 전체 접근 방식은 아마도 누군가가 무언가를 할 수있다, 운명을 정한다. 알았지, 암시 적으로 [없음 [A는 B가] 항상 뭔가를 반환합니다, 하나는 그것을 사용할 수 없습니다. :-(
class AreEqual[A, B] trait LowerPriorityImplicits { implicit def toNo[A : Manifest, B : Manifest]: No[A, B] = No[A, B] } object AreEqual extends LowerPriorityImplicits { implicit def toYes[A, B](implicit ev: A =:= B, m1: Manifest[A], m2: Manifest[B]): Yes[A, B] = Yes[A, B] } case class Yes[A : Manifest, B : Manifest]() extends AreEqual[A, B] { override def toString: String = "Yes(%s, %s)" format (manifest[A].toString, manifest[B].toString) } case class No[A : Manifest, B : Manifest]() extends AreEqual[A, B] { override def toString: String = "No(%s, %s)" format (manifest[A].toString, manifest[B].toString) }
테스트:
scala> implicitly[AreEqual[String, Option[String]]] res0: AreEqual[String,Option[String]] = No(java.lang.String, scala.Option[java.lang.String]) scala> implicitly[AreEqual[String, String]] res1: AreEqual[String,String] = Yes(java.lang.String, java.lang.String)
from https://stackoverflow.com/questions/6909053/enforce-type-difference by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 이 개지도를 병합과 같은 키의 값을 요약하는 가장 좋은 방법은? (0) | 2019.10.29 |
---|---|
[SCALA] HashPartitioner는 어떻게 작동합니까? (0) | 2019.10.29 |
[SCALA] 어떻게 스파크에 dataframe에 RDD 개체를 변환하는 (0) | 2019.10.29 |
[SCALA] 스파크-CSV를 사용하여 하나의 CSV 파일을 쓰기 (0) | 2019.10.29 |
[SCALA] 무엇 =의 차이> () =>, 그리고 단위 => (0) | 2019.10.29 |