Como desenvolvedor Java, o conceito de campo de apoio é um pouco estranho para mim. Dado:
class Sample {
var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0) field = value
}
}
Para que serve este campo de apoio? Os documentos de Kotlin disseram:
As aulas em Kotlin não podem ter campos. No entanto, às vezes é necessário ter um campo de apoio ao usar acessores personalizados .
Por quê? Qual é a diferença em usar o próprio nome das propriedades dentro do configurador, por exemplo. *
class Sample {
var counter = 0
set(value) {
if (value >= 0) this.counter = value // or just counter = value?
}
}
android
kotlin
kotlin-android-extensions
Yudhistira Arya
fonte
fonte
this.counter = value
é o mesmo com o equivalente Java ao ler a documentação de Kotlin.Respostas:
Porque, digamos, se você não tiver uma
field
palavra-chave, não será capaz de definir / obter o valor emget()
ouset(value)
. Ele permite que você acesse o campo de apoio nos acessadores personalizados.Este é o código Java equivalente ao seu exemplo:
class Sample { private int counter = 0; public void setCounter(int value) { if (value >= 0) setCounter(value); } public int getCounter() { return counter; } }
Aparentemente, isso não é bom, pois o setter é apenas uma recursão infinita em si mesmo, nunca mudando nada. Lembre-se no kotlin sempre que você escrever,
foo.bar = value
ele será traduzido em uma chamada setter em vez de umPUTFIELD
.EDITAR: Java tem campos, enquanto Kotlin tem propriedades , que é um conceito de nível bastante superior do que campos.
Existem dois tipos de propriedades: uma com um campo de apoio, outra sem.
Uma propriedade com um campo de apoio armazenará o valor na forma de um campo. Esse campo possibilita o armazenamento de valor na memória. Um exemplo de tal propriedade são as propriedades
first
esecond
dePair
. Essa propriedade mudará a representação na memória dePair
.Uma propriedade sem um campo de apoio terá que armazenar seu valor de outras maneiras além de armazená-lo diretamente na memória. Deve ser calculado a partir de outras propriedades ou do próprio objeto. Um exemplo de tal propriedade é a
indices
propriedade de extensão deList
, que não é apoiada por um campo, mas um resultado calculado com base nasize
propriedade. Portanto, isso não mudará a representação na memóriaList
(o que não pode ser feito porque o Java é estaticamente tipado).fonte
this.counter = value
é o mesmo com java equivalente.field
é mais como um ponteiro ou uma referência a uma variável de membro existente. Como oget/set
imediatamente seguecounter
, portanto, afield
palavra-chave é uma referência acounter
. Direito?Inicialmente, eu também tive dificuldade em entender esse conceito. Portanto, deixe-me explicar com a ajuda de um exemplo.
Considere esta aula de Kotlin
class DummyClass { var size = 0; var isEmpty get() = size == 0 set(value) { size = size * 2 } }
Agora, quando olhamos para o código, podemos ver que ele tem 2 propriedades, isto é -
size
(com acessores padrão) eisEmpty
(com acessores personalizados). Mas tem apenas 1 campo iesize
. Para entender que ele possui apenas 1 campo, vamos ver o equivalente Java dessa classe.Vá para Ferramentas -> Kotlin -> Mostrar Kotlin ByteCode no Android Studio. Clique em Decompile.
public final class DummyClass { private int size; public final int getSize() { return this.size; } public final void setSize(int var1) { this.size = var1; } public final boolean isEmpty() { return this.size == 0; } public final void setEmpty(boolean value) { this.size *= 2; } }
Claramente, podemos ver que a classe java tem apenas funções getter e setter para
isEmpty
, e não há nenhum campo declarado para ela. Da mesma forma, em Kotlin, não há campo de apoio para a propriedadeisEmpty
, já que a propriedade não depende desse campo. Portanto, não há campo de apoio.Agora vamos remover o getter e setter personalizados de
isEmpty
propriedade.class DummyClass { var size = 0; var isEmpty = false }
E o equivalente em Java da classe acima é
public final class DummyClass { private int size; private boolean isEmpty; public final int getSize() { return this.size; } public final void setSize(int var1) { this.size = var1; } public final boolean isEmpty() { return this.isEmpty; } public final void setEmpty(boolean var1) { this.isEmpty = var1; } }
Aqui vemos os campos
size
eisEmpty
.isEmpty
é um campo de apoio porque o getter e o setter daisEmpty
propriedade dependem dele.fonte
field
palavra-chave, é possível que um aprimoramento de linguagem de Kotlin remova essafield
palavra-chave estranha e evite que as almas indefesas caiam no abismo da recursão infinita?Os campos de apoio são bons para executar a validação ou disparar eventos na mudança de estado. Pense nas vezes em que você adicionou código a um setter / getter Java. Os campos de apoio seriam úteis em cenários semelhantes. Você usaria campos de apoio quando precisasse controlar ou ter visibilidade sobre setters / getters.
Ao atribuir o campo com o próprio nome do campo, você está, na verdade, chamando o configurador (ou seja
set(value)
). No exemplo que você tem,this.counter = value
iria recursivamente em set (valor) até que estourássemos nossa pilha. O usofield
ignora o código setter (ou getter).fonte
field
- chave não está em C #, portanto, precisamos de uma explicação melhor do que a que você citou aqui.Meu entendimento é usar o identificador de campo como uma referência ao valor da propriedade em get ou set , quando você deseja alterar ou usar o valor da propriedade em get ou set .
Por exemplo:
class A{ var a:Int=1 get(){return field * 2} // Similiar to Java: public int geta(){return this.a * 2} set(value) {field = value + 1} }
Então:
var t = A() println(t.a) // OUTPUT: 2, equal to Java code: println(t.a * 2) t.a = 2 // The real action is similar to Java code: t.a = t.a +1 println(t.a) // OUTPUT: 6, equal to Java code: println(t.a * 2)
fonte
A terminologia
backing field
é cheia de mistério. A palavra-chave usada éfield
. Osget/set
métodos seguem imediatamente ao lado da variável de membro que está prestes a ser obtida ou definida por meio desse mecanismo de métodos de proteção de porta. Afield
palavra-chave se refere apenas à variável de membro que deve ser definida ou obtida . No momento, Kotlin, você não pode se referir à variável de membro diretamente dentro dos métodos de porta de proteção get ou set porque, infelizmente, resultará em recursão infinita porque irá re-invocar get ou set e, assim, conduzir o tempo de execução para o abismo profundo.No entanto, em C # , você pode referenciar diretamente a variável de membro dentro dos métodos getter / setter. Estou citando esta comparação para apresentar a ideia de que esta
field
palavra-chave é como o Kotlin atual a está implementando, mas espero que seja removida em versões posteriores e nos permita fazer referência direta à variável de membro sem resultar em recursão infinita.fonte