Na linguagem Swift, para inicializar uma instância, é necessário preencher todos os campos dessa classe e somente então chamar superconstrutor:
class Base {
var name: String
init(name: String) {
self.name = name
}
}
class Derived: Base {
var number: Int
init(name: String, number: Int) {
// won't compile if interchange lines
self.number = number
super.init(name)
}
}
Para mim, parece inverso, porque a instância precisa self
ser criada antes da atribuição de valores a seus campos, e esse código dá a impressão de que o encadeamento ocorre apenas após a atribuição. Além disso, a superclasse não possui meios legais de ler os atributos introduzidos de sua subclasse; portanto, a segurança não conta neste caso.
Além disso, muitas outras linguagens, como JavaScript, e até o Objective C, que é um ancestral espiritual do Swift, exigem ligação em cadeia antes do acesso self
, e não depois.
Qual é o motivo por trás dessa escolha para exigir que os campos sejam definidos antes de chamar o superconstrutor?
fonte
self
.Respostas:
No C ++, quando você cria um objeto Derivado, ele inicia como um objeto Base enquanto o construtor Base está em execução; portanto, no momento em que o construtor Base é executado, os membros Derived nem existem. Portanto, eles não precisam ser inicializados e não podem ser inicializados. Somente quando o construtor Base é concluído, o objeto é alterado para um objeto Derivado com muitos campos não inicializados que você inicializa.
No Swift, quando você cria um objeto Derivado, ele é um objeto Derivado desde o início. Se os métodos forem substituídos, o método init da Base já utilizará os métodos substituídos, que podem acessar as variáveis de membro Derivado. Portanto, todas as variáveis de membro Derivado devem ser inicializadas antes da chamada do método Base init.
PS. Você mencionou o Objective-C. No Objective-C, tudo é inicializado automaticamente como 0 / nil / NO. Mas se esse valor não for o valor correto para inicializar uma variável, o método init da Base poderá chamar facilmente um método que será substituído e usar a variável ainda não inicializada com um valor 0 em vez do valor correto. No Objective-C, isso não é uma violação das regras de linguagem (é assim que está definido para funcionar), mas obviamente um bug no seu código. No Swift, esse bug não é permitido pelo idioma.
PS. Há um comentário "é um objeto derivado desde o início ou não é observável devido a regras de linguagem"? A classe Derived inicializou seus próprios membros antes que o método init seja chamado, e esses membros Derived mantêm seus valores. Portanto, é um objeto Derivado no momento em que a base init é chamada, ou o compilador teria que fazer algo bastante bizarro. E logo após o método init da Base ter inicializado todos os membros da instância Base, ele pode chamar funções substituídas e isso provará que é uma instância da classe derivada.
fonte
Isso vem das regras de segurança da Swift, conforme explicado na seção Inicialização em duas fases na página Inicialização do documento de idioma .
Ele garante que todos os campos sejam definidos antes do uso (especialmente ponteiros, para evitar falhas).
O Swift consegue isso com uma sequência de inicialização em duas fases: cada inicializador deve inicializar todos os seus campos de instância e, em seguida, chamar um inicializador de superclasse para fazer o mesmo, e somente depois que isso acontece na árvore esses inicializadores podem deixar o
self
ponteiro escapar, chamar instância métodos ou leia os valores das propriedades da instância.Eles podem fazer uma inicialização adicional, assegurando que o objeto esteja bem formado. Em particular, todos os ponteiros não opcionais terão valores válidos. nulo não é válido para eles.
O objetivo C não é muito diferente, exceto que 0 ou zero é sempre um valor válido; portanto, a primeira fase de inicialização é feita pelo alocador, definindo todos os campos como 0. Além disso, Swift possui campos imutáveis, portanto, eles devem ser inicializados na fase um. . E a Swift aplica essas regras de segurança.
fonte
Considerar
Portanto, não há um design simples que torne o contratante seguro quando métodos virtuais são permitidos ; o Swift evita esses problemas ao exigir a Inicialização em Duas Fases, proporcionando maior segurança ao programador e, ao mesmo tempo, resultando em uma linguagem mais complexa.
Se você pode resolver esses problemas de uma maneira agradável, não passe "Go", prossiga diretamente para a coleção do seu PHd…
fonte