web-dev-qa-db-ja.com

+-Scalaの総称宣言の記号

このリンク でPartialFunctionのドキュメントを見ていた:

trait PartialFunction[-A, +B] extends (A) ⇒ B

たぶん誰かがジェネリック宣言のプラス記号とマイナス記号の重要性を明確にするのを助けることができますか?

46
Ariel T

「+」と「-」はそれぞれ 共変と反変 タイプを意味します。つまり、次のことを意味します。

PartialFunction[-A1, +B1] <:PartialFunction[-A2, +B2]は、A1 :> A2およびB1 <: B2の場合のみ。ここで、<:はサブタイプの関係です。

「-」は通常、入力パラメーターに適用され、「+」は出力に適用されます-C#では、それぞれのキーワードinoutも使用します。さらにいくつかのプリミティブ Javaでの一般的な分散のサポート 存在型に基づいて構築されています-実際には、_ <: SomeType(共分散)または抽象型メンバーtype T <: SomeTypeを使用してそれを行うことができますScalaも同様です。

修飾子がない場合、PartialFunction[A1, B1]PartialFunction[A2, B2]と直接の関係を持ちません(つまり、不変です)。

追伸このような型には、covariant( "+")型を反変の位置にすることはできず(メソッドからのみ返すことができます)、その逆など、いくつかの制限が適用されます。これは Liskov Substitution Principle をサポートするために行われ、「in」/「out」の解釈で自然に理解できます。

また、A => BFunction1の構文糖)自体がco-/contra-varianceを使用していることにも注意してください。

 trait Function1 [-T1, +R] extends AnyRef

これらの関数は、サブタイピングによって拡張できるため、理論的には部分的にも部分的になります(ただし、Scalaがこれらを処理する方法とは異なります)-技術的にはScalaの「合計」FunctionN 、再定義、nullなどを返します。

29
dk14

それは共分散と反分散です。 https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)

基本的に、ジェネリック型については継承がどのように機能するかを示しています。 Scalaからの簡単なサンプルは-trait Seq[+A] +のため、コード

val s: Seq[Person] = Seq[Student]()

studentがPersonを拡張するため、コンパイルされます。 +なしでは機能しません

もう少し複雑なサンプル-

class C[-A, +B] {
  def foo(param: A): B = ???
}

class Person(val name: String)

class Student(name: String, val university: String) extends Person(name)

val sample: C[Student, Person] = new C[Person, Student]
21
Maxim

他の回答を補足するために、ここにscala-langサイトの差異に関するドキュメントへのリンクがあります。

https://docs.scala-lang.org/tour/variances.html

5
Michael Hewson