2016-06-16 3 views
3

Два вопроса:В чем причина ошибки этого типа?

  1. Почему этот код не компилировать? I считаю (но я не уверен на 100%, я, возможно, допустил ошибку), что он правильный.

  2. Что означает сообщение об ошибке? Я смущен, почему ожидаемый тип аргумента - _ -> _ (или, может быть, я просто не знаю, что это значит, _ -> _ в этом случае). Цель этого вопроса - научиться правильно диагностировать это сообщение об ошибке, если я буду снова сталкиваться с ним в будущем.

Код:

Этот код не компилировать с сообщением об ошибке «Не удается преобразовать значение типа 'A -> B' ожидаемого типа аргумента '_ -> _':

class ZipList<A> { 
    let xs: [A] 
    init(xs: [A]) { 
     self.xs = xs 
    } 
    func map<B>(f: A -> B) -> ZipList<B> { 
     return ZipList(xs: self.xs.map(f)) 
    } 
} 

enter image description here

Дополнительная информация:

Сначала я предположил, что проблема была с умозаключения типа, поэтому я попытался выписывая типы в явном виде, но это также не удалось:

enter image description here

enter image description here

Однако это компилируется нормально (единственное отличие от моей первоначальной map версии является <B> передается ZipList инициализатору):

func map4<B>(f: A -> B) -> ZipList<B> { 
    return ZipList<B>(xs: self.xs.map(f)) 
} 

ответ

4

Проблема заключается в том, что, когда вы не укажете явно общий тип параметра ZipList, когда вы обратитесь к нему, компилятор попытается сделать это для вас - а это не всегда исправить.

Как вы уже внутри ZipList<A> класса, компилятор будет пытаться вывести ZipList быть ZipList<A> когда вы опускаете общий параметр (см this question для получения дополнительной информации о поведении).

Поэтому теперь ожидает ввод [A] в ZipList(xs:_) Инициализатором, а это означает, что функция карты выводятся как A -> A, который вы пытаетесь передать A -> B к, вызывая несоответствие типов (поэтому f выделен в качестве проблема в вашей ошибке).

Если вы облегчите вниз ваш пример просто вызывая init() на вашем ZipList без предоставления аргументов, вы увидите более полезное сообщение об ошибке:

class ZipList<A> { 

    init() {} 

    func map<B>() -> ZipList<B> { 
     // error: Cannot convert return expression of type 'ZipList<A>' to 'ZipList<B>' 
     return ZipList() 
    } 
} 

Тот факт, что компилятор полностью игнорирует явное тип аннотации возврата для метода map() является ошибкой и отслеживается SR-1789. Причина, как описано Иордана Rose в комментариях отчета в том, что:

Вроде бы случай мы охотно в предположении, что параметры такие же, как и для self. (Это, как правило, функция, но не тогда, когда он становится на пути других умозаключений.)

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

return ZipList<B>(xs: xs.map(f)) 

Это вынуждает общий параметр, чтобы иметь тип B, поэтому предотвращение Swift из-за неправильного выводя его, позволяя функции map решить.

Что касается того, что сообщение об ошибке «Невозможно преобразовать значение типа„A -> B“ожидаемого типа аргумента«_ -> _»означает, _ в данном случае просто относится к универсальному типу, который компилятор не может Разрешить (не полезное сообщение об ошибке, я знаю). Таким образом, весь компилятор говорит вам, что он ожидает, что функция принимает ввод неизвестного типа и возвращает тот же тип.

Это часто помогает при диагностировании подобных сообщений об ошибках, чтобы разделить выражение на несколько подвыражений и проверить типы для каждого из них, чтобы попытаться найти неправильное совпадение. Это также может помочь упростить пример вниз (например, использовать init() вместо init(xs:[A]) в вашем методе map), пока вы не столкнетесь с более полезным сообщением об ошибке.

+0

Отличный ответ! Спасибо за помощь; в этом есть смысл. –

+0

@MattFenwick Счастлив помочь :) – Hamish

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