Почему вы не можете инициализировать протокол, который имеет реализацию по умолчанию? - PullRequest
0 голосов
/ 12 ноября 2019

Я прочитал В Swift, почему я не могу создать экземпляр протокола, если у него есть инициализатор?

Мой вопрос сосредоточен на том, почему компилятор не может разобраться вваша реализация по умолчанию и инициализировать объект на основе этого?

protocol ViewModel {
    var radius: Int { get }
    init()
}

extension ViewModel {
    var radius: Int { return 2}
    init() {}
}

let v = ViewModel() // ERROR: 

Тип протокола 'ViewModel' не может быть создан

Вопрос1:

Почему Swift не разрешаетванильная инициализация протокола? Почему он должен быть привязан к конкретному типу?

Я понял, что это не конкретный тип. Но почему компилятор не позволяет вам просто создать тип, который является ничем иным, как протоколом в его значении по умолчанию ?! Это потому, что компилятор похож на эй, слушай, а я могу или думать о тебе как об интерфейсе / протоколе или как о реальном типе. Я не могу думать о тебе как об обоих !? Вы или что-то реальное в памяти или просто черновик.

Если бы язык мог проверить, обеспечивает ли расширение реализацию для всех требований, то имеет ли смысл разрешить инициализацию этого как особый случай ? (Я понимаю, что это не так, но интересно, что единственное, что нужно, чтобы заставить это работать). Если так, то почему?

Кроме того, я попытался сделать это вместо:

protocol ViewModel {
    var radius: Int { get }
    init()
}

extension ViewModel {
    var radius: Int { return 2}
    init() {
        self.init() // Line A: 
    }
}

struct ReallyNothing: ViewModel {}

let v = ReallyNothing()

Если я закомментирую LineA, я получу ошибку

'self.init' isnВызов всех путей перед возвратом из инициализатора

Вопрос2:

ПОЧЕМУ? почему init должен вызывать self.init(), это похоже на рекурсивный цикл.

Ответы [ 3 ]

1 голос
/ 12 ноября 2019

Это не имеет ничего общего с тем, имеет ли ViewModel init. Это связано с тем, что ViewModel является . Это протокол.

Протокол не является объектом. нет такой вещи как экземпляр протокола. Что бы это значило «создать экземпляр» протокола? Ничего. Вы можете создать экземпляр:

  • перечисления
  • структуры
  • или класса

Протокол не является ни одним из этих,Вы не можете создать экземпляр протокола.

ViewModel - это протокол. Таким образом, вы не можете сделать пример этого. Фраза ViewModel() не имеет смысла. И компилятор говорит вам об этом.

0 голосов
/ 12 ноября 2019

Вы в основном спрашиваете, почему тип протокола не может действовать как абстрактный класс и конкретный класс? Почему компилятор не допустил такого?

Помимо очевидного ответа, что протокол не является конкретным типом, поэтому, когда вы вызовете Protocol.init(), компилятор не будет знать, какой конкретный типинициализировать

В то время как компилятор компилятора может проверять соответствие расширения (аналогично тому, как он проверяет, соответствует ли конкретный тип всем требованиям). Он не проверяет, реализовали ли вы все требования протокола в расширении. Так что полагаться на расширение не может быть и речи. Следовательно, компилятор не позволяет этого. Я предполагаю, что компилятор мог бы сделать это, но, поскольку вы можете не захотеть проверять все требования протокола в расширении протокола, то становится невозможным инициировать только на основе самого протокола.

Кроме того, если компилятор выполнил такую ​​проверку даже тогда, когда у вас есть что-то вроде:

func setupUI(with viewModel: ViewModel)

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

0 голосов
/ 12 ноября 2019

https://docs.swift.org/swift-book/LanguageGuide/Protocols.html

Протоколы являются чертежами и не содержат реализации, поэтому вы не можете их инициализировать.

Класс соглашается с протоколом и должен обеспечивать фактическую реализацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...