2015-11-25 5 views
0

Компилятор запутывается перегруженным методом определения, и я не могу найти способ прояснить мое намерение достаточно.Удаление двусмысленности определения перегруженного метода

У меня есть следующий код:

val part: (QueryParams) => List[ResultMap] = (partOf.find _).andThen(makeMap)

find метод перегружен:

def find(params: QueryParams): List[U] = ... 
def find(params: QueryParams, flattener: U => T): List[T] = ... 

код работает отлично до тех пор, пока был один Definiton из find. Так как я должен был добавить второй find Definiton с 2 Params, компилятор генерирует сообщение об ошибке:

Error:(15, 31) ambiguous reference to overloaded definition, both method find in trait DataFetcher of type (params: ...QueryParams)List[...Parser] and method find in trait DataFetcher of type (params: ...QueryParams, flattener: ...Parser => ...ResultTuple)List[...ResultTuple] match expected type ? val part: Fetcher = (partOf.find _).andThen(makeMap) ^

ИМХО нет никакой двусмысленности. Тип part определен для принятия одного аргумента типа QueryParams. Существует только один метод, принимающий один QueryParams. U и T - это разные типы, а makeMap ожидает List[U]. В нем нет значений implicits, значений по умолчанию или varargs.

Есть ли способ прояснить мое намерение для компилятора?

EDIT: один из способов устранения неоднозначности является введение посреднического значения, уточняя ожидаемый тип расширения эты:

val find: (QueryParams) => List[ResultTuple] = partOf.find _ 
val part: (QueryParams) => List[ResultMap] = find andThen makeMap 

Но поскольку makeMap только принимающий List[ResultTuple] я стил не получаем причину для предполагаемой двусмысленности и предпочел бы не вводить дополнительную ценность. Любые разъяснения?

ответ

2

Во-первых, важно понимать, что заднее подчеркивание является преднамеренным конструктивным решением для предотвращения programmer mistakes. Единственное исключение - это когда тип явно объявлен.

Вот пример, иллюстрирующий этот момент.

object A { 
    def add(a: Int)(b:Int): Int = a + b 
    val x: Int => Int = add(5) // compiles fine 
    val y = add(5) // produces a compiler error 
} 

То же самое касается вашего вопроса. Поскольку вы не указываете промежуточный тип, когда вы пишете find _, должен ли компилятор указать тип QueryParams => List[ResultTuple] (как и следовало ожидать), или он должен быть (QueryParams, U => T) => List[ResultTuple]? Обратите внимание, что конечное подчеркивание не соответствует одному аргументу, оно просто возвращает метод к функции. Когда объявляется тип, вы можете отменить нижнее подчеркивание и написать find, где вы бы написали find _.

Я вижу из вашего редактирования, что вы обнаружили, что работает промежуточное значение с объявленным типом. Другой (слегка неуклюжий) способ прояснить ваши намерения заключается в следующем.

val part: (QueryParams) => List[ResultMap] = (x => partOf.find(x)).andThen(makeMap) 
+0

+1 Да, лямбда с вариантом args также работает, спасибо за наконечник, модем. Если ошибка компилятора преднамеренно, я бы ожидал, что она подтолкнет меня в правильном направлении, но я не понимаю, что это за принцип дизайна.Было бы здорово, если бы двусмысленность могла быть решена путем предоставления типа метода для расширения - неуклюжей версии 'find [QueryParams]: List [ResultTuple] _' – kostja

+0

@kostja Поскольку вы не указываете промежуточный тип, когда вы пишете 'find _', если компилятор выводит тип' QueryParams => List [ResultTuple] '(как и следовало ожидать) или должен быть' (QueryParams, U => T) => List [ResultTuple] ' ? Обратите внимание, что конечное подчеркивание не соответствует одному аргументу, оно просто возвращает метод к функции. – moem

Смежные вопросы