#dart
Вопрос:
Минимальный воспроизводимый код:
class Foo {
Foo();
factory Foo.named() => Foo();
}
class Bar extends Foo {
Bar() : super.named(); // Error
}
Поскольку async-await
в фабричном конструкторе ничего нет, и он мгновенно вызывает конкретный конструктор, так почему же ему не разрешается использовать фабричный конструктор подобным образом?
До нулевой безопасности, null
может быть возвращен из factory
конструктора, но это уже не тот случай. Итак, я думаю, что теперь должен быть разрешен конструктор фабрики.
Ответ №1:
заводская функция может возвращать подкласс, что означает, что она может вызывать функцию инициализации подкласса.
если подкласс self может вызывать функцию super.factory, то он становится циклическим.
Ответ №2:
Вызов порождающего конструктора создает новый объект, затем запускает конструктор и конструкторы суперкласса для инициализации этого нового объекта. Они являются инициализаторами, которые инициализируют объект, созданный (теперь часто неявным) new
оператором.
Суперконструктор, связанный цепочкой (не перенаправляющим) генеративным конструктором, вызывается для инициализации одного и того же объекта и обеспечения полной инициализации его полей, прежде чем предоставлять кому-либо доступ к этому объекту.
Вызов конструктора фабрики не создает никакого нового объекта, он просто выполняет тело этого конструктора, который может делать все, что может обычный код. (Это может включать или не включать вызов конструктора генерации для создания объекта. Он также может просто бросить и никогда не создавать никаких объектов.) Конструктор фабрики не может получить доступ this
, потому что нет «текущего объекта», прежде чем он его вернет.
Давайте предположим, что Foo
у int foo = 42;
этого есть поле. Конструктор фабрики, подобный Foo.named
here, создает новый объект путем вызова Foo()
— порождающего конструктора. Когда вы это сделаете new Bar()
, вы создадите новый Bar
объект и попросите суперконструкторов инициализировать этот объект. Конструктор named
фабрики не имеет доступа к этому новому объекту , который был бы создан путем вызова new Bar()
, он не может получить доступ this
и не может помочь инициализировать foo
поле этого объекта. Он создает новый, не связанный Foo
объект, и теперь у вас есть 1) частично инициализированный Bar
объект и 2) Foo
объект, ни один из которых не может быть результатом вызова Bar
конструктора.
Ваши генеративные конструкторы должны вызывать генеративный конструктор суперкласса, который делает то же самое до тех пор, пока не достигнет Object
конструктора. Это единственный способ убедиться, что вновь созданный объект полностью инициализирован.
Комментарии:
1. «Именованный конструктор не имеет доступа к объекту, который будет создан путем вызова new Bar ()» — я заблудился в этой строке. Не могли бы вы, пожалуйста, объяснить это немного подробнее.
2. Трудно описать гипотетику, которая не имеет смысла. Я добавил еще немного текста. В принципе, конструктор генерации автоматически получает объект «это» для инициализации, используя свой список инициализаторов, а конструктор фабрики этого не получает, поэтому он не может инициализировать создаваемый объект. Таким образом, вы не можете связать шаг инициализации генерации с помощью конструктора фабрики, потому что он не может выполнять то, что должен выполнять конструктор генерации: инициализировать новый объект.
3. Спасибо, теперь все гораздо яснее. Хотя я не понял в этой строке ни одной элементарной вещи
... ask the super-constructors to initialize that object
. О чемobject
мы здесь говорим,Bar
? И если это такBar
, то так ли все работает в Dart, что, когда мы делаемsuper(...)
это из конструктора базового класса, он в основном передает экземпляр базового класса суперклассу для инициализации, т. Е. инициализирует ли суперкласс экземпляр базового класса? Я думаю, что это то, что вы также упомянули в комментарии (поскольку я не из CS, мне немного сложно понять вещи при первом чтении).4. Когда вы это сделаете
new Bar()
, новыйBar
объект немедленно создается в неинициализированном состоянии. Вызывается конструктор генерации дляBar
, который должен инициализировать любые поля , введенные сBar
помощью инициализаторов полей, инициализирующих формалов или назначений списка инициализаторов. Затем вызывается конструктор генерации суперкласса для инициализации того же объекта, только для любых полей, введенных суперклассом,Foo
здесь. Затем вызывается его конструктор суперкласса (которыйObject
здесь является конструктором). Только тогда объект будет готов .5. Короче говоря: генеративные конструкторы не создают объекты.
new
Оператор в генеративном конструкторе создает объект, затем генеративные конструкторы инициализируют объект, причем каждый суперкласс получает свою очередь для инициализации своих собственных полей. Вот почему должна быть цепочка порождающих (инициализирующих) конструкторов вплоть доObject
.
Ответ №3:
Одна из основных целей factory
конструктора — разрешить возврат существующего экземпляра. Это в принципе несовместимо с конструктором производного класса, который должен создать новый объект. (Я полагаю, что это не обязательно должно быть так; вы могли бы представить себе дизайн, в котором два производных экземпляра фактически наследуются от общего экземпляра базового класса. Однако это было бы большой дополнительной работой для чего-то малопригодного, и это могло бы очень сбить с толку.)
Кроме того, одна из других основных целей factory
конструктора заключается именно в том, чтобы предотвратить создание подкласса класса, сделав все factory
неконструкторы закрытыми.