UFO ET IT

스칼라-제네릭의 모든 대 밑줄

ufoet 2020. 11. 11. 20:59
반응형

스칼라-제네릭의 모든 대 밑줄


Scala에서 다음 Generics 정의의 차이점은 무엇입니까?

class Foo[T <: List[_]]

class Bar[T <: List[Any]]

내 직감은 그들이 거의 같지만 후자가 더 분명하다고 말합니다. 전자는 컴파일되지만 후자는 컴파일되지 않지만 정확한 차이점에 대해 손가락을 댈 수없는 경우를 찾고 있습니다.

감사!

편집하다:

믹스에 다른 것을 던져도 되나요?

class Baz[T <: List[_ <: Any]]

좋아요, 그냥 댓글을 올리는 대신 제가해야한다고 생각 했어요. 죄송합니다. TL; DR을 끝까지 건너 뛰려면 시간이 오래 걸립니다.

Randall Schulz가 말했듯이 여기 _에 실존 적 유형의 약어가 있습니다. 즉,

class Foo[T <: List[_]]

에 대한 속기

class Foo[T <: List[Z] forSome { type Z }]

Randall Shulz의 답변이 언급 한 것과는 반대로 (전체 공개 :이 게시물의 이전 버전에서도 잘못되었습니다. 지적한 Jesper Nordenberg 덕분에) 이것은 다음과 같지 않습니다.

class Foo[T <: List[Z]] forSome { type Z }

다음과 같지도 않습니다.

class Foo[T <: List[Z forSome { type Z }]]

주의하십시오. (이전의 바보가 보여 주듯이) Randall Shulz의 답변이 참조한 기사의 저자가 직접 잘못 이해하고 (댓글 참조) 나중에 수정했습니다. 이 기사의 주요 문제점은 표시된 예제에서 실존 적 사용이 타이핑 문제에서 우리를 구할 수 있다고 가정하지만 그렇지 않다는 것입니다. 코드를 확인하고 컴파일 compileAndRun(helloWorldVM("Test"))하거나 compileAndRun(intVM(42)). 네, 컴파일되지 않습니다. 단순히 compileAndRungeneric을 A만들면 코드가 컴파일되고 훨씬 간단 해집니다. 요컨대, 그것은 실존주의와 그것이 무엇을 위해 좋은지에 대해 배우기에 가장 좋은 기사는 아닐 것입니다 (저자 자신은 기사가 "정리가 필요하다"는 코멘트에서 인정합니다).

따라서 http://www.artima.com/scalazine/articles/scalas_type_system.html , 특히 "Existential types"및 "Variance in Java and Scala"라는 섹션을 읽는 것이 좋습니다 .

이 기사에서 알아야 할 중요한 점은 비 공변 유형을 다룰 때 실존성이 유용하다는 것입니다 (일반 자바 클래스를 다룰 수 있다는 점을 제외하고). 여기에 예가 있습니다.

case class Greets[T]( private val name: T ) {
  def hello() { println("Hello " + name) }
  def getName: T = name
}

이 클래스는 일반 (불변 임)이지만 hello실제로 유형 매개 변수를 사용하지 않는다는 것을 알 수 있습니다 (와 달리 getName). 따라서 I 인스턴스를 얻으면 Greets항상 호출 할 수 있어야합니다. T이다. Greets인스턴스 를 가져 오고 해당 hello메서드를 호출 하는 메서드를 정의하려면 다음을 시도해 볼 수 있습니다.

def sayHi1( g: Greets[T] ) { g.hello() } // Does not compile

물론, T여기에서 갑자기 나오는 것처럼 이것은 컴파일되지 않습니다 .

그럼, 메소드를 제네릭으로 만들어 봅시다 :

def sayHi2[T]( g: Greets[T] ) { g.hello() }
sayHi2( Greets("John"))
sayHi2( Greets('Jack))

좋습니다. 여기에서 실존성을 사용할 수도 있습니다.

def sayHi3( g: Greets[_] ) { g.hello() }
sayHi3( Greets("John"))
sayHi3( Greets('Jack))

작동합니다. 따라서 대체로 sayHi3유형 매개 변수 (에서와 같이)보다 실존 적 (에서와 같이 ) 을 사용하는 것이 실제 이점이 없습니다 sayHi2.

그러나 이것은 Greets다른 제네릭 클래스에 대한 유형 매개 변수로 표시되는 경우 변경됩니다 . 예를 들어 Greets(다른 T) 의 여러 인스턴스를 목록 에 저장하고 싶다고 가정 해 보겠습니다 . 해 보자:

val greets1: Greets[String] = Greets("John")
val greets2: Greets[Symbol] = Greets('Jack)
val greetsList1: List[Greets[Any]] = List( greets1, greets2 ) // Does not compile

마지막 줄 때문에 컴파일되지 않습니다 Greets불변이다, 그래서, Greets[String]그리고 Greets[Symbol]A와 처리 할 수없는 Greets[Any]에도 불구 String하고 Symbol모두 확장 Any.

OK, let's try with an existential, using the shorthand notation _:

val greetsList2: List[Greets[_]] = List( greets1, greets2 ) // Compiles fine, yeah

This compiles fine, and you can do, as expected:

greetsSet foreach (_.hello)

Now, remember that the reason we had a type checking problem in the first place was because Greets is invariant. If it was turned into a covariant class (class Greets[+T]) then everything would have worked out of the box and we would never have needed existentials.


So to sum up, existentials are useful to deal with generic invariant classes, but if the generic class does not need to appear itself as a type parameter to another generic class, chances are that you don't need existentials and simply adding a type parameter to your method will work

Now come back(at last, I know!) to your specific question, regarding

class Foo[T <: List[_]]

Because List is covariant, this is for all intents and purpose the same as just saying:

class Foo[T <: List[Any]]

So in this case, using either notation is really just a matter of style.

However, if you replace List with Set, things change:

class Foo[T <: Set[_]]

Set is invariant and thus we are in the same situation as with the Greets class from my example. Thus the above really is very different from

class Foo[T <: Set[Any]]

The former is a shorthand for an existential type when the code doesn't need to know what the type is or constrain it:

class Foo[T <: List[Z forSome { type Z }]]

This form says that the element type of List is unknown to class Foo rather than your second form, which says specifically that the List's element type is Any.

Check out this brief explanatory blog article on Existential Types in Scala (EDIT: this link is now dead, a snapshot is available at archive.org)

참고URL : https://stackoverflow.com/questions/15186520/scala-any-vs-underscore-in-generics

반응형