0

次の例を考えてみましょう

abstract class Lookup(val code:String,val description:String)

class USState(code:String, description:String, val area:Symbol)
  extends Lookup(code,description)

class Country(code:String, description:String, val postCode:String)
  extends Lookup(code,description)

class HtmlLookupSelect(data:List[Lookup]) {
  def render( valueMaker:(Lookup) => String ) =
    data.map( (l) => valueMaker(l) )
}

val countries = List(
  new Country("US","United States","USA"),
  new Country("UK","Unites Kingdom","UK"),
  new Country("CA","Canada","CAN"))

def lookupValue(l:Lookup) = l.description
def countryValue(c:Country) = c.description + "(" + c.postCode + ")"

val selector = new HtmlLookupSelect(countries) //Doesn't throw an error
selector.render(countryValue) //Throws an error

HtmlLookupSelectコンストラクタ パラメータとして Lookup オブジェクトのリストが必要です。HtmlLookupSelect オブジェクトの作成中に、county オブジェクトのリストが渡されます。コンパイラは、オブジェクトCountryのサブクラスとして認識されるため、エラーをスローしません。Lookup

しかし、次の行で、Country をパラメーターの型として (予期される Lookup ではなく) メソッドを呼び出そうとすると、Type mismatchエラーが発生します。なぜこうなった?

4

1 に答える 1

3

countryValueCountrytoからの関数String(実際には関数に eta 展開されるメソッドですが、現在は関係ありません)、つまり aFunction1[Country, String]です。

renderを期待しFunction1[Lookup, String]ます。

だから私たちが答えたい質問は

与えられCountryたのはサブタイプですLookup

Function1[Country, String]サブタイプFunction1[Lookup, String]ですか?

それに答えるために、 の定義を見てみましょうFunction1:

trait Function1[-T1, +R] extends AnyRef

-T1?を参照してください。それが入力パラメーターであり、-その入力パラメーターFunction1反変で、出力パラメーターが共変である平均です。

したがって、if A <: B(<:サブタイプの関係はどこにある) とR <: S その後

Function1[B, R] <: Function[A, S]

あなたの例では、Country <: Lookupそう

Function1[Country, String] </: Function[Lookup, String]

言い換えると、関数は、それ以上のことを約束し (共変の戻り値の型)、それ以上は必要としない (反変の入力型) 場合、別のサブタイプです。

たとえば、 を受け取ってAnimalを返す関数は、 を受け取ってを返すApple関数が必要な場合はいつでも使用できます。より正式にDogFruit

Dog <: Animal
Fruit <: Apple
Function1[Animal, Apple] <: Function1[Dog, Fruit]

ただし、その逆は正しくありません。関数が犬を処理して果物を返す場合、動物を処理してリンゴを返すために使用することはできません。

于 2015-09-16T10:43:18.910 に答える