scala类型参数化混淆

时间:2015-09-16 10:35:18

标签: scala parameterization

考虑以下示例

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对象时,会将一个县对象列表传递给它,并且编译器不会抛出错误,因为它将Country识别为Lookup的子类

但是在下一行中,当我尝试使用Country作为参数类型(而不是预期的Lookup)调用方法时,出现Type mismatch错误。为什么会这样?

1 个答案:

答案 0 :(得分:3)

countryValue是从CountryString的函数(实际上是一种将eta扩展为函数但现在不相关的方法),即Function1[Country, String]

render需要Function1[Lookup, String]

所以我们要回答的问题是

  

鉴于Country是[{1}}

的子类型      

Lookup的子类型是Function1[Country, String]

为了回答这个问题,让我们看一下Function1[Lookup, String]的定义:

Function1

请参阅trait Function1[-T1, +R] extends AnyRef ?这是输入参数,-T1表示-在输入参数中逆变,在输出参数中协变。< / p>

所以,如果Function1(其中A <: B是子类型关系)和<: 然后

R <: S

在您的示例中,Function1[B, R] <: Function[A, S] 如此

Country <: Lookup

换句话说,当函数承诺不少(共变量返回类型)并且它不再需要(反变量输入类型)时,函数是另一个函数的子类型。

例如:只要需要Function1[Country, String] </: Function[Lookup, String] 并返回Animal的函数,就可以使用带Apple并返回Dog的函数。更正式的

Fruit

但相反的情况并非如此:如果你的功能处理狗并返回任何水果,它肯定不能用于处理任何动物并返回苹果。