2012-12-04 1 views
18

불변 Set 콜렉션에서 toSeq을 호출하면 ArrayBuffer이됩니다.스칼라의 toSeq가 불변 Set를 변경 가능한 ArrayBuffer로 변환하는 이유는 무엇입니까?

scala> Set(1,2,3).toSeq // returns Seq[Int] = ArrayBuffer(1, 2, 3) 

놀랍습니다. 스칼라가 불변의 데이터 구조를 사용하는 것에 중점을 두어, ArrayBuffer 대신에 Vector 또는 List과 같은 변경 불가능한 시퀀스를 되 찾을 것으로 기대된다. set 요소의 반환 된 순서는 물론 정의되지 않아야하지만 순서가 변경 가능해야하는 의미 론적 이유는없는 것으로 보입니다.

일반적으로 나는 스칼라 연산이 명시 적으로 변경 가능한 것을 요구하지 않는 한 항상 불변의 결과를 생성 할 것으로 기대한다. 이것은 내 가정 이었지만 여기서는 잘못된 것이 었습니다. 실제로 ArrayBuffer이 예기치 않게 존재하여 match 문에서 런타임 오류가 발생하는 한 시간을 보냈습니다. 내 픽스는 Set(...).toSeqSet(...).toList으로 변경했지만 해킹과 같은 느낌이 들었습니다. 그 시점에서 특히 목록이 필요한 응용 프로그램에 대한 정보가 없기 때문입니다.

Set(...).toSeq은 스칼라 구현에서 결함이있는 객체를 반환하거나 여기에 오해의 원칙이 있습니까?

이것은 스칼라 2.9.2입니다.

+0

2.10-RC2에 고정'스칼라> 서열 (1,2,3) .toSeq' -> '이 res0 서열 [지능] = 목록 (1, 2, 3) ' – senia

+0

@senia, Seq (1,2,3) .toSeq 대신'Set (1,2,3) .toSeq'을 사용하셨습니까? –

+1

변경을 위해 투표하십시오 : [SI-6570] (https://issues.scala-lang.org/browse/SI-6570) –

답변

11

Here은 Seq가 immutable.Seq를 의미해야하는지 여부에 관한 최근 스레드입니다.

롤랜드 쿤 :

collection.Seq 가지고 있지 뮤 테이터는 모든 유효한 방어에 있지!

변경 가능한 varargs의 예는 다소 부적절합니다. 최근

,

scala> Set(1,2,3) 
res0: scala.collection.immutable.Set[Int] = Set(1, 2, 3) 

scala> res0.toSeq 
res1: Seq[Int] = ArrayBuffer(1, 2, 3) 

scala> res0.to[collection.immutable.Seq] 
res2: scala.collection.immutable.Seq[Int] = Vector(1, 2, 3) 
+0

현재 답변은 "논쟁의 여지가 있습니다"링크 된 스레드가 좋은 것을 제공합니다 토론 이유. 반 (反) mutabilists 자신의 길을 가고있는 것으로 보인다 때문에 원래 질문에 대한 의견뿐만 아니라 링크를 확인하십시오. –

10

나는 약간 이상하다고 동의하지만, 그것이 결함이라고 생각하지 않는다. 첫째,이 사항을 고려하십시오 Set.toSeq의 컴파일시의 형태가

() => Seq[Int] 

하지

() => ArrayBuffer[Int] 

ArrayBuffer

그냥 반환 된 객체의 런타임 타입 될 일이다 (아마도 Set.toSeqArrayBuffer에 추가하기 때문에 그런 다음 변환하지 않고 그냥 반환합니다.)

그럼에도 불구하고 toSeq이 가변 개체를 돌려주고 있지만 캐스팅 또는 패턴 일치가 ArrayBuffer이 아니므로 실제로 변경할 수 없습니다. 실제 "이상한"부분은 스칼라에서 패턴 일치를 허용한다는 것입니다. 임의의 클래스). (당신은 Set이 객체를 붙잡고 그것을 변형시키지 않는다고 믿어야합니다.하지만 이것은 틀림없는 가정이라고 생각합니다.)

변경할 수있는 형식은 변경할 수없는 형식보다 엄격히 더 구체적입니다. 또는 변경 가능한 모든 객체는 불변 객체로 취급 될 수 있습니다. 불변 객체는 getter를 가지며 변경 가능한 객체는 getter setter를 갖지만 여전히 getter가 있습니다. 물론

,이는 악용 될 수 있습니다

val x = new Seq[Int] { 
    var n: Int = 0 
    def apply(k: Int) = k 
    def iterator = { 
     n += 1 
     (0 to n).iterator 
    } 
    def length = n 
} 

x foreach println _ 
0 
1 

x foreach println _ 
0 
1 
2 

하지만, 음, 너무 많은 것들을 할 수 있습니다.