2016-09-24 3 views
1

저는 스칼라를 처음 접했고 몇 가지 간단한 문제로 인해 어려움을 겪고 있습니다. , 첫째로, 나는 이러한 클래스의 요소에 액세스 할 수 없습니다 그래서 leftchild, head 필드를 구현 :스칼라에서 추상 클래스 필드 생성 및 액세스

abstract class IntSet { 
    def incl(x: Int): IntSet 
    def contains(x: Int): Boolean 
} 

class Empty extends IntSet { 
    def contains(x: Int): Boolean = false 
    def incl(x: Int): IntSet = new NonEmpty(x, new Empty, new Empty) 
} 

class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet { 
    val head = elem 
    val leftChild = left 
    val rightChild = right 

    def contains(x: Int): Boolean = 
    if (x < elem) left contains x 
    else if (x > elem) right contains x 
    else true 

    def incl(x: Int): IntSet = 
    if (x < elem) new NonEmpty(elem, left incl x, right) 
    else if (x > elem) new NonEmpty(elem, left, right incl x) 
    else this 
} 

val my_intset = new NonEmpty(5, new Empty, new Empty) 
my_intset.head 
val new_intset = my_intset.incl(10) 
new_intset.head 

를 그리고 두 가지 문제로 실행 : 나는 다음과 같이 정수를 저장하는 간단한 이진 트리를 구현하고있어 및 rightchild. 어느 누구도 my_intset에 액세스 할 수 있습니다. 그러나 incl이 호출되면 개체 유형이 변경되고 new_intset은 이제 IntSet이되어 다시 요소에 액세스 할 수 없게됩니다. 그러한 필드가 항상 액세스 할 수 있도록하려면 어떻게해야합니까?

둘째, incl을 호출하면 개체 유형이 변경된다는 것이 불편합니다. 사용자 관점에서 볼 때이 두 객체는 ​​모두 IntSet의 인스턴스라고 생각합니다. 그게 내 의도입니다. 나는 염려 할 만하니? 이 동작을 제어 할 수있는 방법이 있습니까?

답변

2

스칼라에서는 이러한 유형의 조작에 Abstract Data TypesPattern Matching을 사용할 수 있습니다.

예제를 조금 수정할 수 있습니다. 우리는 종류의 기본 구조를 정의하는 sealed trait를 만듭니다 :

sealed trait IntSet { 
    val head: Option[Int] 
    val left: IntSet 
    val right: IntSet 

    def incl(x: Int): IntSet 
    def contains(x: Int): Boolean 
} 

을 그리고 지금 우리가 구체적인 사례를 추가 할 것입니다 상속/클래스 객체 : Emptycase object 얼마나

case class NonEmpty(head: Option[Int], left: IntSet, right: IntSet) extends IntSet { 
    def contains(x: Int): Boolean = { 
    if (x < head.getOrElse(0)) left contains x 
    else if (x > head.getOrElse(0)) right contains x 
    else true 
    } 

    def incl(x: Int): IntSet = { 
    if (x < head.getOrElse(0)) NonEmpty(head, left incl x, right) 
    else if (x > head.getOrElse(0)) NonEmpty(head, left, right incl x) 
    else this 
    } 
} 

case object Empty extends IntSet { 
    override val head: Option[Int] = None 
    override val left: IntSet = Empty 
    override val right: IntSet = Empty 

    def contains(x: Int): Boolean = false 
    def incl(x: Int): IntSet = NonEmpty(Some(x), Empty, Empty) 
} 

참고. 모든 비어있는 IntSet은 동일하므로 하나의 표현 만 필요하므로 인스턴스를 할당 할 필요가 없습니다. leftright 값을 나타내는 데 어떻게 사용했는지 유의하십시오.

지금, 다시 원래의 예에 가고, 이것은 잘 작동합니다 :

또한
def main(args: Array[String]): Unit = { 
    val myIntSet = new NonEmpty(Some(5), Empty, Empty) 
    println(myIntSet.head) 
    val newIntSet = myIntSet.incl(10) 
    println(newIntSet.right.head) 
} 

, 우리는 우리가 거기에 패턴 일치가 기본이되는 구체적인 유형으로 작업 할 수있는 IntSet에서 작동 할 :

def isEmpty(intSet: IntSet): Boolean = intSet match { 
    case Empty => true 
    case NonEmpty(_, _, _) => false 
} 

보조 메모로 head을 나타내는 데 Option[Int]을 사용했습니다. headEmpty을 0으로 설정하는 대신 0을 사용하면 Int을 사용할 수 있습니다.

당신이 당신과 비슷한 예를 원한다면, 내가 제안 looking at the implementation for List[+A]


대수는 다음과 같을 수 있습니다 당신이 운영하는 유형을 정의하는 추가 예 : 지금

sealed trait BinaryTree 
case class Node(value: Int, left: BinaryTree, right: BinaryTree) extends BinaryTree 
case object Empty extends BinaryTree 

def incl(tree: BinaryTree, x: Int): BinaryTree = { 
    tree match { 
    case Node(value, left, right) => 
     if (x < value) Node(value, incl(left, x), right) 
     else if (x > value) Node(value, left, incl(right, x)) 
     else tree 
    case Empty => Node(x, Empty, Empty) 
    } 
} 

과 :

def main (args: Array[String]): Unit = { 
    val n = Node(0, Node(1, Empty, Empty), Node(2, Empty, Empty)) 
    val x = incl(n, 3) 
    println(x) 
} 

수율 :

Node(0,Node(1,Empty,Empty),Node(2,Empty,Node(3,Empty,Empty))) 
+0

좋아요!도와 주셔서 대단히 감사합니다. – aspaceo

+0

@aspaceo 환영합니다. –

관련 문제