2014-12-09 1 views
0

스칼라에서는 toString과 같은 몇 가지 메소드를 제외하고는 List [String]과 같은 클래스를 원합니다.리스트와 거의 같은 클래스를 어떻게 정의 할 수 있습니까?

내가 지금 가지고있는 것은 fqn0 ++ fqn1list0 ++ list1List'; it currently gives a LinearSeq [문자열]`주는 것처럼, 나에게 FQN을 제공하는 제가하고 싶은 것은, 그러나

case class FQN(val names : List[String]) extends LinearSeq[String] { 

     def this(params : String*) { this(List(params : _*)) } 

     override def toString() : String = { 
       names.reduce((a,b) => b++"."++a) 
     } 

     override def apply(i : Int) = names.apply(i) 

     override def length() = names.length 

     override def tail = new FQN(names.tail) 

     override def head = names.head 

     override def isEmpty = names.isEmpty 

     def ::(str : String) = new FQN(str :: names) 

    } 

입니다. 그래서 내가 바라는대로 뭔가가 아닙니다.

또한 FQN을 케이스 클래스로 사용하여 equals 및 hashCode를 원하는 방식으로 가져 오지만 이것이 최선의 방법인지 여부는 확실하지 않습니다.

List과 같은 클래스를 만드는 가장 좋은 방법은 무엇입니까? 그러나 특정 방법은 다르게 구현됩니까?

+1

쉽게 사용자 지정 기능을 추가 목록에 암시 적 클래스를 정의 할 수 있습니다. – Ryan

+0

암묵적인 클래스가 어떻게 도움이되는지 잘 모르겠습니다. { \t 재정 데프 toString() : 문자열 = { \t \t names.reduce ("."(A, B) => B ++ ++ A) \t : 나는'암시 클래스 FQN (목록 [문자열] 이름을) 시도 \t} \t}'그렇지만'fqn0 ++ fqn1'은'++'가 FQN의 멤버가 아니라는 오류를줍니다. –

+0

나는 FQN을 전혀 사용하지 않는다고 말하면서, 결과 타입 (예 :'String')이나 다른'List'를 반환하는 함수를 암시 적 클래스에 작성합니다. 스칼라 컬렉션을 구현하는 것은 힘들 수 있습니다. – Ryan

답변

1

내 용기는 전문 FQN 모음을 실행하지 떨어져 아마 더 나은 것을 말해하지만 effectivly FQN의 인터페이스에서 해당 작업을 제거 FQN의 내부 구현의 일환으로 컬렉션을 숨 깁니다. 제 말은 세계가 실제로 FQNSeq으로보고해야하며 해당 작업을 모두 사용할 수 있는지 또는 어카운팅 목록 ++에 대한 작업이 FQN 인 경우에만 작업을 ++에만 추가 할 수 있을지 여부를 스스로 물어야합니다. 의 인터페이스.

그러나 스칼라의 사람들은 자신의 컬렉션을 일반화하는 데 큰 역할을 한 것처럼 보였고 자신의 컬렉션을 구현하는 것은 큰 고통처럼 보이지 않았습니다. documentation I posted in a comment은 자신의 컬렉션을 구현할 때 코드를 재사용하는 방법을 설명하며이를 읽는 것이 좋습니다.

간단히 말해서, 형체를 xxxLike 형태의 이름으로 혼합하고자 할 수 있습니다. 구체적인 경우 LinearSeqLike[String, FQN]을 입력하고 newBuilder: mutable.Builder[String, FQN] 메서드를 재정의하면 drop과 같은 메서드가 FQN으로 반환됩니다.

빌더만으로는 충분하지 않습니다. map과 같은 메소드 (및 놀랍게도 ++)는 컬렉션에 포함 된 요소를 컬렉션에서 지원할 필요가없는 다른 유형으로 매핑 할 수 있습니다. 귀하의 예에서 FQN ("foo"). map (_. length)은 유효한 FQN이 아니므로 결과는 FQN 일 수 없지만 FQN("Foo").map(_.toLowercase)은 합법입니다 (적어도 유형과 관련하여). 이 문제는 내재 된 CanBuildFrom 값을 범위로 가져옴으로써 해결됩니다.

최종 구현은 다음과 같을 수 있습니다 :

final class FQN private (underlying: List[String]) extends LinearSeq[String] with LinearSeqLike[String, FQN] { 
    def apply(i: Int): String = underlying.apply(i) 

    def length = underlying.length 

    /** From the documentation of {LinearSeqLike}: 
    * Linear sequences are defined in terms of three abstract methods, which are assumed 
    * to have efficient implementations. These are: 
    * {{{ 
    *  def isEmpty: Boolean 
    *  def head: A 
    *  def tail: Repr 
    * }}} 
    */ 
    override def isEmpty: Boolean = underlying.isEmpty 

    override def head: String = underlying.head 

    override def tail: FQN = FQN.fromSeq(underlying.tail) 

    override def newBuilder: mutable.Builder[String, FQN] = FQN.newBuilder 

    def ::(str: String) = new FQN(str :: underlying) 

    override def toString(): String = { 
    underlying.mkString(".") 
    } 
} 

object FQN { 

    implicit def canBuildFrom: CanBuildFrom[FQN, String, FQN] = 
    new CanBuildFrom[FQN, String, FQN] { 
     def apply(): mutable.Builder[String, FQN] = newBuilder 
     def apply(from: FQN): mutable.Builder[String, FQN] = newBuilder 
    } 

    def newBuilder: mutable.Builder[String, FQN] = 
    new ArrayBuffer mapResult fromSeq 

    def fromSeq(s: Seq[String]): FQN = new FQN(s.toList) 

    def apply(params: String*): FQN = fromSeq(params) 

} 
아마
0

이 @Ryan 및 @KuluLimpa 의견을 바탕으로 (또는 어쨌든 그들에 대한 이해에서), 여기에 이제 List[String]로 할 수있는 모든 접근

type FQN = List[String] 

implicit class FQNWithFQNToString(names : List[String]) { 
    def fqnToString() : String = { 
     names.reduce((a,b) => b++"."++a) 
    } 
} 

, 당신은 FQN로 할 수 있습니다. 예를 들어 fqn1++fqn2FQN입니다. 원하는 문자열을 얻으려면 fqn.fqnToString을 사용할 수 있습니다.

나는 두 가지 이유

  • 약한 유형 검사

    에 대한 만족보다는이 답변 덜 찾을 수 있습니다. Strings의 이전 목록이 FQN으로 처리되면 오류가 없습니다. 특히 QN (한정된 이름)을 정의 할 수없고 FQN이 필요한 경우 QN을 사용하면 컴파일 시간 오류가 발생할 수 있습니다.
  • 이제 FQN을 문자열로 변환하는 두 가지 방법이 있습니다. 나는 각 경우에 올바른 것을 사용해야한다. List[String]QN이라는 다른 이름을 만들면 개체를 문자열로 변환하는 세 가지 방법이 있습니다. 이것은 객체 지향적이지 않은 느낌을 받기 시작합니다.
+0

이것은 다소 기능 프로그래밍 적이기 때문에 비 객체 지향적 인 것으로 느껴질 것입니다.이 구현은 암시 적 클래스가 함수를 인터페이스의 일부로 만드는 약간의 차이점을 제외하고는 'fqnToString (names : List [String])'함수를 추가하는 것과 매우 유사합니다 목록의 이것은 반드시 나쁜 것은 아니지만 특정 경우에는 두 개의 toString 메소드를 사용하는 것이 이상적이지 않다는 것에 동의합니다. 문제는 인터페이스에 새로운 기능을 추가하고 싶지 않지만 기존의 동작을 변경한다는 것입니다. 따라서 기능적인 방법으로는 만족할만한 솔루션을 얻을 수 없습니다. –

+0

제가 생각할 수있는 유일한 만족스러운 해결책은 초기 구현을 수행하고 다시 정의해야하는 모든 메서드를 재정의하는 것입니다. 이는 상당히 복잡한 Scala 컬렉션을 다루면서 특히 고통 스럽습니다. 아마 [이 문서] (http://www.scala-lang.org/docu/files/collections-api/collections-impl_0.html)가 도움이 될 수 있습니까? 그러나 'FQN'이 먼저 인터페이스를 구현해야하는 이유를 다시 생각해 봐야합니다! 'FQN'은'LinearSeq [String]'이 예상되는 곳에 다형 적으로 사용될 필요가 있습니까? 단순히 구현의 일부로 컬렉션을 숨길 수 없습니까? –

+0

@KuluLimpa 스칼라 컬렉션의 아키텍처를 자세히 읽도록하겠습니다. 하지만 기능적 스타일 대 객체 지향 스타일의 문제라고 생각하지 않습니다. 예를 들어 Haskell에서'[String]'을 기반으로'newtype'을 생성 한 다음 새로운 유형이'Monad'를 유도하지만'Show'는 생성하지 못합니다. –

관련 문제