То, что вы видите, называется контравариантностью. Из-за этого параметры функции должны быть контравариантными:
class HisSubClass extends MyClass
val his = new HisSubClass
f7(his) // his is accepted as MyClass
Теперь f4
будет вызываться с чем-то, что не является MySubClass
, что будет ошибкой.
Случай Seq
/ List
работает, потому что все наоборот. List
является подклассом Seq
.
val af2: (List[_]) => Boolean = af0
как
val aff0: (MyClass) => Boolean = (s) ⇒ { s eq null }
val aff2: (MySubClass) => Boolean = aff0
Обещание (контракт)
Что мне очень помогло понять разницу между параметром и возвращаемым значением, так это то, что я думал об объявлениях типов как об обещаниях (или контрактах). Возвращаемое значение является ковариантным, поскольку вы пообещали, что возвращаемое значение будет иметь тип MyClass
, и, предоставив MySubClass
в подклассе, вы по-прежнему выполняете свое обещание. Обещание, что вы примете параметр типа MyClass
, а затем попытка объявить член подкласса, принимающий только MySubClass
, означает попытку сузить обещание, чего вы не можете (подкласс должен полностью реализовать родительский класс).
В вашем примере в f4
вы обещали, что функция будет передана MySubClass
в качестве параметра. Когда вы пытаетесь присвоить это f7
, вы пытаетесь нарушить это обещание, поскольку вы можете передать любое MyClass
в f4
, вызвав его через f7
.
person
Suma
schedule
05.07.2018