복붙노트

[SCALA] 어떻게 스칼라의 타입 삭제 주위를받을 수 있나요? 또는, 왜 나는 내 컬렉션의 형식 매개 변수를 얻을 수 없다?

SCALA

어떻게 스칼라의 타입 삭제 주위를받을 수 있나요? 또는, 왜 나는 내 컬렉션의 형식 매개 변수를 얻을 수 없다?

그것은 당신이 목록 [지능]을 인스턴스화하는 경우, 그것은 목록 [라고하지만, 당신이 당신의 인스턴스가 목록 있는지 확인할 수 있습니다, 당신은 그것의 개별 요소는 지능 있는지 확인 할 수있는 스칼라에 삶의 슬픈 사실 쉽게 검증 할 수있는 지능] :

scala> List(1,2,3) match {
     | case l : List[String] => println("A list of strings?!")
     | case _ => println("Ok")
     | }
warning: there were unchecked warnings; re-run with -unchecked for details
A list of strings?!

-unchecked 옵션은 유형의 삭제에 정면으로 비난을 넣습니다 :

scala>  List(1,2,3) match {
     |  case l : List[String] => println("A list of strings?!")
     |  case _ => println("Ok")
     |  }
<console>:6: warning: non variable type-argument String in type pattern is unchecked since it is eliminated by erasure
        case l : List[String] => println("A list of strings?!")
                 ^
A list of strings?!

이유는 즉, 나는 주위 어떻게받을 수 있나요?

해결법

  1. ==============================

    1.자바 가상 머신 (JVM)이, 자바와는 달리, 제네릭을하지 않았기 때문에 스칼라는 유형 소거로 정의 하였다. 이것은 실행시에 만 클래스가 존재하지의 유형 매개 변수 것을 의미한다. 예에서, JVM은 아니지만이 목록은 지능과 파라미터 것을하는 scala.collection.immutable.List을 처리 알고있다.

    자바 가상 머신 (JVM)이, 자바와는 달리, 제네릭을하지 않았기 때문에 스칼라는 유형 소거로 정의 하였다. 이것은 실행시에 만 클래스가 존재하지의 유형 매개 변수 것을 의미한다. 예에서, JVM은 아니지만이 목록은 지능과 파라미터 것을하는 scala.collection.immutable.List을 처리 알고있다.

    다행히, 당신이 그 주위를 얻을 수 있습니다 스칼라의 기능이있다. 그것은 매니페스트입니다. 매니페스트가있는 인스턴스의 유형을 나타내는 객체 클래스입니다. 이러한 경우는 객체이기 때문에, 당신은 그들을 주변에 통과를 저장하고, 일반적으로 그들에 메서드를 호출 할 수 있습니다. 암시 적 매개 변수의 지원과 함께, 그것은 매우 강력한 도구가된다. 예를 들어, 다음의 예를 보자

    object Registry {
      import scala.reflect.Manifest
    
      private var map= Map.empty[Any,(Manifest[_], Any)] 
    
      def register[T](name: Any, item: T)(implicit m: Manifest[T]) {
        map = map.updated(name, m -> item)
      }
    
      def get[T](key:Any)(implicit m : Manifest[T]): Option[T] = {
        map get key flatMap {
          case (om, s) => if (om <:< m) Some(s.asInstanceOf[T]) else None
        }     
      }
    }
    
    scala> Registry.register("a", List(1,2,3))
    
    scala> Registry.get[List[Int]]("a")
    res6: Option[List[Int]] = Some(List(1, 2, 3))
    
    scala> Registry.get[List[String]]("a")
    res7: Option[List[String]] = None
    

    요소를 저장할 때, 우리는 너무 그것의 "매니페스트"를 저장합니다. 매니페스트는 그 인스턴스 스칼라 유형을 나타내는 클래스입니다. 이러한 개체는 전체, 파라미터 화 된 형태를 테스트 할 수있게 JVM 않는,보다 더 많은 정보를 가지고있다.

    매니페스트 (manifest)는 여전히 진화하는 기능입니다 점에 유의. 그 한계의 예를 들어, 그것은 현재 분산에 대해 아무것도 알고, 모든 것을 공동으로 변형 있다고 가정하지 않습니다. 나는 현재 개발 완료됩니다, 스칼라 반사 라이브러리를 한 번 더 안정적이고 견고한 얻을 것으로 기대.

  2. ==============================

    2.당신은이 TypeTags를 사용하여 수행 할 수 있습니다 (단 이미 언급으로,하지만 난 단지 명시 적으로 맞추는 것) :

    당신은이 TypeTags를 사용하여 수행 할 수 있습니다 (단 이미 언급으로,하지만 난 단지 명시 적으로 맞추는 것) :

    import scala.reflect.runtime.universe._
    def matchList[A: TypeTag](list: List[A]) = list match {
      case strlist: List[String @unchecked] if typeOf[A] =:= typeOf[String] => println("A list of strings!")
      case intlist: List[Int @unchecked] if typeOf[A] =:= typeOf[Int] => println("A list of ints!")
    }
    

    또한 ClassTags 사용하여이 작업을 수행 할 수 있습니다 (에 의존 할 필요에서 당신을 저장 스칼라을-반영) :

    import scala.reflect.{ClassTag, classTag}
    def matchList2[A : ClassTag](list: List[A]) = list match {
      case strlist: List[String @unchecked] if classTag[A] == classTag[String] => println("A List of strings!")
      case intlist: List[Int @unchecked] if classTag[A] == classTag[Int] => println("A list of ints!")
    }
    

    당신은 그 자체로 형식 매개 변수 A가 제네릭 형식이 될 기대하지 않는 ClassTags 너무 오래 사용할 수 있습니다.

    불행하게도 그것은 조금 자세한 그리고 당신은 컴파일러 경고를 억제하기 위해 @unchecked 주석이 필요합니다. TypeTag은 미래에 컴파일러에 의해 자동으로 패턴 일치에 통합 될 수 있습니다 https://issues.scala-lang.org/browse/SI-6517

  3. ==============================

    3.당신은 뒤에있는 결과를 얻을 수 볼품에서 Typeable 타입의 클래스를 사용할 수 있습니다,

    당신은 뒤에있는 결과를 얻을 수 볼품에서 Typeable 타입의 클래스를 사용할 수 있습니다,

    샘플 REPL 세션,

    scala> import shapeless.syntax.typeable._
    import shapeless.syntax.typeable._
    
    scala> val l1 : Any = List(1,2,3)
    l1: Any = List(1, 2, 3)
    
    scala> l1.cast[List[String]]
    res0: Option[List[String]] = None
    
    scala> l1.cast[List[Int]]
    res1: Option[List[Int]] = Some(List(1, 2, 3))
    

    인 - 범위 Typeable 인스턴스 가능한 주어진 가능한 캐스팅 동작은 정확한 WRT 소거 될 것이다.

  4. ==============================

    4.나는 기본적으로 일치 문에서 사용할 수있는 래퍼 클래스의 타입 삭제 문제로 고통 것 매개 변수 유형을 포장, 사용이 제한된 상황에서 충분 비교적 간단한 해결책을했다.

    나는 기본적으로 일치 문에서 사용할 수있는 래퍼 클래스의 타입 삭제 문제로 고통 것 매개 변수 유형을 포장, 사용이 제한된 상황에서 충분 비교적 간단한 해결책을했다.

    case class StringListHolder(list:List[String])
    
    StringListHolder(List("str1","str2")) match {
        case holder: StringListHolder => holder.list foreach println
    }
    

    이것은 예상되는 출력이 원하는 유형, 문자열 목록에 우리의 경우 클래스의 내용을 제한합니다.

    더 자세한 사항은 여기에 : http://www.scalafied.com/?p=60

  5. ==============================

    5.스칼라 유형의 삭제 문제를 극복 할 수있는 방법이있다. 2 (분산)를 일치 1과 극복 유형 소거 일치하는 입력 소거를 극복 매칭, 분산을 포함하여 유형을 래핑하는 몇 가지 헬퍼를 코딩하는 방법에 대한 몇 가지 설명이있다.

    스칼라 유형의 삭제 문제를 극복 할 수있는 방법이있다. 2 (분산)를 일치 1과 극복 유형 소거 일치하는 입력 소거를 극복 매칭, 분산을 포함하여 유형을 래핑하는 몇 가지 헬퍼를 코딩하는 방법에 대한 몇 가지 설명이있다.

  6. ==============================

    6.나는 다른 멋진 언어의 한계에 대한 약간 더 나은 해결 방법을 발견했다.

    나는 다른 멋진 언어의 한계에 대한 약간 더 나은 해결 방법을 발견했다.

    스칼라에서 입력 삭제의 문제는 배열 발생하지 않습니다. 나는 예를 들어 이것을 보여 쉽게 생각합니다.

    우리가 (INT, 문자열)의 목록이 있다고 가정 해 봅시다, 그 다음은 유형 삭제 경고를 제공

    x match {
      case l:List[(Int, String)] => 
      ...
    }
    

    이 문제를 해결하려면, 먼저 케이스 클래스를 생성 :

    case class IntString(i:Int, s:String)
    

    다음 패턴 일치로 그런 짓을 :

    x match {
      case a:Array[IntString] => 
      ...
    }
    

    이는 완벽하게 작동하는 것 같다.

    이 대신 목록의 배열 작업을 코드에서 작은 변화가 필요하지만 큰 문제가되지 않습니다.

    배열 [(INT, 문자열)] 여전히 형식 삭제 경고를 줄 것이다, 그래서 (예, IntString에) 새로운 컨테이너 클래스를 사용하는 것이 필요하다 : 케이스에게를 사용하는 것이 있습니다.

  7. ==============================

    7.자바는 실제 요소의 유형을 알고하지 않기 때문에, 나는 그것이 가장 유용한 단지 목록 [_]를 사용하는 것으로. 그런 다음 경고는 사라지고 코드는 현실을 설명합니다 - 그것은 알 수없는 무언가의 목록입니다.

    자바는 실제 요소의 유형을 알고하지 않기 때문에, 나는 그것이 가장 유용한 단지 목록 [_]를 사용하는 것으로. 그런 다음 경고는 사라지고 코드는 현실을 설명합니다 - 그것은 알 수없는 무언가의 목록입니다.

  8. ==============================

    8.이것은 적합한 해결 방법 있는지 궁금 해요 :

    이것은 적합한 해결 방법 있는지 궁금 해요 :

    scala> List(1,2,3) match {
         |    case List(_: String, _*) => println("A list of strings?!")
         |    case _ => println("Ok")
         | }
    

    그것은 "빈 목록"의 경우와 일치하지 않지만, 컴파일 에러가 아닌 경고를 제공!

    error: type mismatch;
    found:     String
    requirerd: Int
    

    반면에이 작동하는 것 같다 ....

    scala> List(1,2,3) match {
         |    case List(_: Int, _*) => println("A list of ints")
         |    case _ => println("Ok")
         | }
    

    그것은 더 나은 또는 내가 여기에 요점을 놓치고 좀 아닌가?

  9. ==============================

    9.아니 솔루션하지만 방법은 모두 양탄자 아래를 청소하지 않고 함께 살 : @unchecked 주석을 추가. 여기를 참조하십시오 - http://www.scala-lang.org/api/current/index.html#scala.unchecked

    아니 솔루션하지만 방법은 모두 양탄자 아래를 청소하지 않고 함께 살 : @unchecked 주석을 추가. 여기를 참조하십시오 - http://www.scala-lang.org/api/current/index.html#scala.unchecked

  10. ==============================

    10.어떻게 런타임에서 내 목록의 형식의 String 표현을 얻을 방법 : 나는에 문제를 일반화된다 대답을 추가하고 싶었

    어떻게 런타임에서 내 목록의 형식의 String 표현을 얻을 방법 : 나는에 문제를 일반화된다 대답을 추가하고 싶었

    import scala.reflect.runtime.universe._
    
    def whatListAmI[A : TypeTag](list : List[A]) = {
        if (typeTag[A] == typeTag[java.lang.String]) // note that typeTag[String] does not match due to type alias being a different type
            println("its a String")
        else if (typeTag[A] == typeTag[Int])
            println("its a Int")
    
        s"A List of ${typeTag[A].tpe.toString}"
    }
    
    val listInt = List(1,2,3)
    val listString = List("a", "b", "c")
    
    println(whatListAmI(listInt))
    println(whatListAmI(listString))
    
  11. ==============================

    11.패턴 일치 가드를 사용하여

    패턴 일치 가드를 사용하여

        list match  {
            case x:List if x.isInstanceOf(List[String]) => do sth
            case x:List if x.isInstanceOf(List[Int]) => do sth else
         }
    
  12. from https://stackoverflow.com/questions/1094173/how-do-i-get-around-type-erasure-on-scala-or-why-cant-i-get-the-type-paramete by cc-by-sa and MIT license