Ох ... Вы не делаете ничего плохого. Но только что обнаружил небольшую ошибку, которой я не ожидал. Мы должны создать экземпляр любого шеф-повара следующим образом:
new Chef[EmptyPizza]()
Я исправлю это в статье через минуту, но чтобы объяснить себя, на самом деле у меня были некоторые конструкторы в объекте case Chef, определяющие следующее:
def apply(): Chef[Pizza.EmptyPizza] = new Chef[Pizza.EmptyPizza]()
Затем я подумал, что не повредит их удалить, поскольку они не добавляли никаких дополнительных концепций, но, напротив, их было бы трудно прочитать любому разработчику, не использующему Scala. У меня также был конструктор Chef, определенный как частный.
Видите ли, моя ошибка связана с определением иерархии типов в Scala. Оказывается, в Scala есть тип, который является подтипом любого другого типа и называется Ничего :
В этом случае компилятор Scala пытается привязать каждую реализацию к наиболее конкретному из возможных типов. Поскольку компилятор совершенно не знает, какую привязку мы хотим установить в этих случаях, он выбирает Nothing
.
Но это становится еще хуже. Поскольку Nothing
является подтипом всего, то это также подтип FullPizza
.
Затем, когда мы его строим, он просто работает.
Самый простой способ решить эту проблему - просто ограничить построение класса Chef, как я делал раньше: ограничить конфиденциальность конструктора Chef и построить его с помощью определенных конструкторов в сопутствующем объекте.
С другой стороны, мы могли бы использовать классы типов для решения этой проблемы. И я мог придумать множество других сложных методов решения этой проблемы, все они зависят от объема решения.
Я думаю, что я просто исправлю примеры шеф-повара в статье и отсылаюсь к этому комментарию для получения дополнительной информации.
На самом деле это прекрасный пример того, как вывод типов может быть довольно легко реализован на нашем пути, и мы этого не заметим.
Действительно хороший улов! Спасибо!