Swift: не удается преобразовать значение типа «SomeType <T>» в ожидаемый тип аргумента «SomeType <_>» - PullRequest
0 голосов
/ 11 февраля 2020

Я использую дженерики для создания библиотеки подкачки, где у меня есть код, похожий на этот (упрощенный):

struct PageData<T> {
    let item: T
    let pageNumber: Int
}

protocol PagedServiceProvider: class {
    func fetchPage<ItemType>(page: Int, completion: @escaping (PageData<ItemType>?) -> Void)
}


class TestPagedServiceProvider<ItemType>: PagedServiceProvider {
    var pageData: PageData<ItemType>?

    func fetchPage<ItemType>(page: Int, completion: @escaping (PageData<ItemType>?) -> Void) {
        completion(pageData) // COMPILATION ERROR HERE
    }
}

вызов completion(pageData) вызывает следующую ошибку:

Невозможно преобразовать значение типа PageData<ItemType>? в ожидаемый тип аргумента PageData<_>?

Этот метод обхода с as? избавляет от ошибки:

class TestPagedServiceProvider<ItemType>: PagedServiceProvider {
    var pageData: PageData<ItemType>?

    func fetchPage<ItemType>(page: Int, completion: @escaping (PageData<ItemType>?) -> Void) {
        completion(pageData as? PageData<ItemType>)
    }
}

Также если var pageData: PageData<ItemType>? объявлен как локальная переменная внутри метода fetchPage<ItemType>..., ошибка также исчезнет.

ПРИМЕЧАНИЕ: Эта сущность предоставляет дополнительный контекст.

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

Может ли это быть областью действия типов заполнителей (ItemType в методе fetchPage<ItemType>... не совпадает с ItemType для класса TestPagedServiceProvider<ItemType>)?

Я пытался дать им разные имена и использовать выражения where безрезультатно.

Ответы [ 3 ]

1 голос
/ 15 февраля 2020

Следующий код работал для меня.

struct PageData<T> {
    let item: T
    let pageNumber: Int
}

protocol PagedServiceProvider: class {
    associatedtype T
    var pageData: PageData<T>? { get set }
    func fetchPage(page: Int, completion: @escaping (PageData<T>?) -> Void)
}


class TestPagedServiceProvider: PagedServiceProvider {

    var pageData: PageData<String>?

    func fetchPage(page: Int, completion: @escaping (PageData<String>?) -> Void) {
        completion(pageData)
    }

}

0 голосов
/ 15 февраля 2020

Ваша подпись типа говорит, что вызывающий может передать любой тип как ItemType, но затем вам требуется, чтобы закрытие приняло PageData<String>?.

fetchPage на самом деле не является универсальным c (он не может принимать типы, выбранные вызывающей стороной), поэтому вы не можете утверждать, что это так. То, что вы имеете в виду, это удалить <ItemType> и сказать то, что вам нужно:

func fetchPage(page: Int, completion: @escaping (PageData<String>?) -> Void) {
              ^^                                          ^^^^^^

Это, однако, нарушает ваш протокол PagedServiceProvider, потому что этот протокол требует, чтобы TestPagedServiceProvider принимал абсолютно любой ItemType, а это не , Вам нужно решить, что вы на самом деле имеете в виду. Здесь вы можете иметь в виду протокол со связанным типом, который представляет собой тип, который реализация выбирает вместо вызывающего.

protocol PagedServiceProvider: class {
    associatedtype ItemType
    func fetchPage(page: Int, completion: @escaping (PageData<ItemType>?) -> Void)
}

Однако это создает некоторые головные боли, поскольку теперь PagedServiceProvider не может быть легко помещен в массиве (это уже не конкретный тип). То, как вы справляетесь с этим, во многом зависит от того, какую проблему вы на самом деле решаете. Не существует общего решения, которое всегда уместно.

0 голосов
/ 14 февраля 2020

Я думаю, что приведенный ниже код будет работать для вас. Я передал String как тип Generi c при создании экземпляра объекта PageData.

func fetchPage<String>(page: Int, completion: @escaping (PageData<String>?) -> Void) {

        let page = PageData<String>(item: "Item", pageNumber: 1)
        completion(page)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...