2016-01-05 2 views
4

Я получаю странную ошибку типа, связанные в моем Swift кода:«тип выражения неоднозначный без дополнительного контекста» ошибки в Swift закрытии

типа выражения является неоднозначным без больше контекста.

Это происходит, даже если я предоставляю полную информацию о типе.

Код, воспроизводящий его.

У меня есть 2 структуры:

struct Person{ 
    let name_ : String 
    let address_ : Address 
} 

struct Address { 
    let street_ : String 
    let city_ : String 
} 

Я тогда создать структуру, которая содержит 2 функции, чтобы получить и установить address из Person:

struct Lens<A,B> { 
    let extract: (A)->B 
    let create: (B,A) -> A 
} 

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

let lens : Lens<Person, Address> = 
Lens(
    extract: {(p:Person)->Address in 
     return p.address_}, // here's the error 
    create: {Person($0.name_, 
     Address(street_: $1, city_: $0.address_.city_))}) 

Не только тип параметра первого замыкания указан в типе объектива, но также и в самом закрытии.

Что происходит ????

+0

В закрытии «create:» имеется несколько ошибок: Отсутствующие метки меток («Лицо (имя_: ...) , address_: ...) 'и' street _: $ 1' не имеет смысла, потому что '$ 1' не является строкой. –

ответ

3

Пока он предлагает ошибку в extract, это действительно было в create. $0 и $1 - назад. Вы имеете в виду $0.name_, но $0create закрытие B, Address, но name_ является собственностью компании Person.Я думаю, что вы имели в виду:

let lens : Lens<Person, Address> = Lens(
    extract: { $0.address_ }, 
    create: { Person(name_: $1.name_, address_: Address(street_: $0.street_, city_: $1.address_.city_)) } 
) 

Или вы можете переопределить Lens:

struct Lens<A, B> { 
    let extract: (A) -> B 
    let create: (A, B) -> A // note, A & B swapped 
} 

И тогда вы можете сделать:

let lens : Lens<Person, Address> = Lens(
    extract: { $0.address_ }, 
    create: { Person(name_: $0.name_, address_: Address(street_: $1.street_, city_: $0.address_.city_)) } 
) 

Или, возможно, вы имели в виду:

let lens : Lens<Person, Address> = Lens(
    extract: { $0.address_ }, 
    create: { Person(name_: $0.name_, address_: $1) } 
) 

Таким образом, create использует как улицу, так и город поставленного адреса. (Для меня нет смысла использовать улицу адреса, но не город.)

2

Ваша инициализация lens будет работать, используя форму, как следующее:

let lens = Lens<Person, Address>(
    extract: {p in p.address_}, 
    create: {(a,p) in Person(name_: p.name_, address_: Address(street_: a.street_, city_: p.address_.city_))}) 

Как отметил Мартин R, единственная ошибка на самом деле были в create закрытия. Когда вы вызываете инициализаторы по умолчанию для своей структуры, вам необходимо предоставить внешние имена (= внутренние имена) для всех аргументов (даже первого) по умолчанию (это отличается от обычных функций, где вы можете опустить внешнее имя для первого аргумент функции). Также убедитесь, что вы указали правильные типы аргументов для инициализатора.

Замечание выше, что вам не нужно вводить тип замыкания ((p:Person)->Address in ...), так как Свифт может вывести (и ожидает этого) из замка: p in ... хватает (см. Пример выше). Или, еще более сжатые, опускайте явные имена переменных в своих закрытиях и используйте вместо них ссылки $0 и $1 (ожидаемые аргументы), как в решении Robs.

+0

Аргумент« extract: »правильный,' {(p: Person) -> Address in return p .address_} '* - это замыкание правильного типа. Ошибки есть только в аргументе« create: ». –

+0

@MartinR Хорошо, я пропустил это, спасибо! – dfri

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