Pochodzące i setery w Kotlinie

86

Na przykład w Javie mogę samodzielnie pisać gettery (generowane przez IDE) lub używać adnotacji, takich jak @Getter w lombok - co było dość proste.

Kotlin ma jednak domyślnie metody pobierające i ustawiające . Ale nie rozumiem, jak ich używać.

Chcę to zrobić, powiedzmy - podobnie jak w Javie:

private val isEmpty: String
        get() = this.toString() //making this thing public rises an error: Getter visibility must be the same as property visibility.

Jak więc działają gettery?

nutella_eater
źródło

Odpowiedzi:

142

Metody pobierające i ustawiające są generowane automatycznie w Kotlinie. Jeśli napiszesz:

val isEmpty: Boolean

Odpowiada następującemu kodowi Java:

private final Boolean isEmpty;

public Boolean isEmpty() {
    return isEmpty;
}

W twoim przypadku modyfikator dostępu prywatnego jest zbędny - isEmpty jest domyślnie prywatny i może być dostępny tylko przez getter. Kiedy próbujesz uzyskać właściwość isEmpty obiektu, wywołujesz metodę get w rzeczywistości. Aby lepiej zrozumieć metody pobierające / ustawiające w Kotlinie: dwie poniższe próbki kodu są równe:

var someProperty: String = "defaultValue"

i

var someProperty: String = "defaultValue"
    get() = field
    set(value) { field = value }

Chcę również zwrócić uwagę, że thisgetter nie jest twoją własnością - jest to instancja klasy. Jeśli chcesz uzyskać dostęp do wartości pola w getterze lub setterze, możesz użyć do tego zarezerwowanego słowa field:

val isEmpty: Boolean
  get() = field

Jeśli chcesz mieć tylko metodę get w dostępie publicznym - możesz napisać ten kod:

var isEmpty: Boolean
    private set 

ze względu na prywatny modyfikator w pobliżu metody dostępu set możesz ustawić tę wartość tylko w metodach wewnątrz obiektu.

Cortwave
źródło
16
In your case the private access modifier is redundantW jaki sposób? Doc Kotlin mówi, że domyślny modyfikator jest publiczny. kotlinlang.org/docs/reference/visibility-modifiers.html
@Nic, tak, wydaje się, że to pole publiczne, ale pod maską nazywasz metodę gettera
Cortwave
val isEmpty: BooleanNie zostanie skompilowany jako isEmpty nie jest jeszcze zainicjowany, prawda? Dopiero zaczynam uczyć się Kotlina. Co się dzieje z get() = field?
Shubham A.
1
@Chiara val's have no setter
chroder
@chroder tak, masz rację, chyba źle przeczytałem ... komentarz został usunięty. Dzięki za zwrócenie uwagi
Chiara
30

Zasady dotyczące modyfikatorów widoczności metod dostępu do właściwości są następujące:

  • Widoczność vari valwłaściwość pobierająca powinny być dokładnie takie same, jak widoczność właściwości, więc możesz tylko jawnie powielić modyfikator właściwości, ale jest to zbędne:

    protected val x: Int
        protected get() = 0 // No need in `protected` here.
    
  • Widoczność varwłaściwości ustawiająca powinna być taka sama lub mniej dopuszczalna niż widoczność właściwości:

    protected var x: Int
        get() = 0
        private set(x: Int) { } // Only `private` and `protected` are allowed.
    

W Kotlinie dostęp do właściwości jest zawsze uzyskiwany za pośrednictwem metody pobierającej i ustawiającej, dlatego nie ma potrzeby tworzenia właściwości privatez publicakcesoriami, takimi jak w Javie - jej pole zapasowe (jeśli jest obecne) jest już prywatne. Tak więc modyfikatory widoczności w akcesoriach właściwości są używane tylko po to, aby widoczność ustawiacza była mniej dopuszczalna:

  • W przypadku właściwości z polem zapasowym i domyślnymi metodami dostępu:

    var x = 0 // `public` by default
        private set
    
  • W przypadku właściwości bez pola zapasowego:

    var x: Int // `public` by default
        get() = 0
        protected set(value: Int) { }
    
Klawisz skrótu
źródło
Czy można ustawić i uzyskać różne typy? Ustawienie x równe some "Some String"i zwrócenie, powiedzmy, długości 11ciągu?
Carel
@Carel, nie, na razie ten przypadek użycia nie jest obsługiwany: metody dostępu do właściwości powinny działać dokładnie z typem właściwości. Używanie innego typu jest objęte oddzielną właściwością kopii zapasowej
skrótem klawiszowym
Cholera, Kotlin jest tak bardzo bliski Pythonowi, że myślisz, że zadziała, gdy przypomnisz sobie, że został wpisany ... i poderżniesz sobie gardło.
Carel
Dzięki za modyfikatory dostępu. Usunąłem privateze zmiennej i stał się dostępny z innej klasy za pomocą metody getter.
CoolMind
Gdy używam kombinacji „var x // private set”, pojawia się komunikat „Private setters nie jest dozwolony dla otwartych właściwości”. Rozwiązany przez zadeklarowanie jako „ostateczna zmienna x”
Tom,
14

1) Przykład domyślny setteri getterdla nieruchomości firstName w Kotlinie

class Person {
    var firstName: String = ""
            get() = field       // field here ~ `this.firstName` in Java or normally `_firstName` is C#
            set(value) {
                field = value
            }

}

Za pomocą

val p = Person()
p.firstName = "A"  // access setter
println(p.firstName) // access getter (output:A)

JEŚLI twój setterlub getterjest dokładnie taki sam powyżej, możesz go usunąć, ponieważ jest niepotrzebny

2) Przykład ustawiający i pobierający niestandardowy.

const val PREFIX = "[ABC]"

class Person {

    // set: if value set to first name have length < 1 => throw error else add prefix "ABC" to the name
    // get: if name is not empty -> trim for remove whitespace and add '.' else return default name
    var lastName: String = ""
        get() {
            if (!field.isEmpty()) {
                return field.trim() + "."
            }
            return field
        }
        set(value) {
            if (value.length > 1) {
                field = PREFIX + value
            } else {
                throw IllegalArgumentException("Last name too short")
            }
        }
}

Za pomocą

val p = Person()
p.lastName = "DE         " // input with many white space
println(p.lastName)  // output:[ABC]DE.
p.lastName = "D" // IllegalArgumentException since name length < 1

Więcej
Zaczynam uczyć się Kotlina od Javy, więc jestem zagubiony fieldi propertyponieważ w Javie nie ma property.
Po jakimś wyszukiwaniu widzę fieldiw propertyKotlinie wyglądam jak C # ( Jaka jest różnica między polem a właściwością? )

Oto niektóre istotne stanowisko, które mówią o fieldi propertyw Java i Kotlin.
czy java ma coś podobnego do właściwości C #?
https://blog.kotlin-academy.com/kotlin-programmer-dictionary-field-vs-property-30ab7ef70531

Popraw mnie, jeśli się mylę. Mam nadzieję, że to pomoże

Phan Van Linh
źródło
Dziękuję, to naprawdę mi pomogło!
marcode_ely
8

Metoda pobierania w kotlin jest domyślnie publiczna, ale można ustawić metodę ustawiającą na prywatną i ustawić wartość za pomocą jednej metody wewnątrz klasy. Lubię to.

/**
* Created by leo on 17/06/17.*/

package foo
class Person() {
var name: String = "defaultValue"
               private set

fun foo(bar: String) {
    name = bar // name can be set here
       }
}

fun main(args: Array<String>) {
  var p = Person()
  println("Name of the person is ${p.name}")
  p.foo("Jhon Doe")
  println("Name of the person is ${p.name}")
}
Lalit Behera
źródło
5

Możesz zobaczyć ten samouczek, aby uzyskać więcej informacji:

Jeszcze jeden samouczek Kotlin dla programistów Androida

Nieruchomości

W świecie Kotlina klasy nie mogą mieć pól, tylko właściwości. Słowo kluczowe var mówi nam, że właściwość jest zmienna, w przeciwieństwie do val. Zobaczmy przykład:

class Contact(var number: String) {

   var firstName: String? = null
   var lastName: String? = null
   private val hasPrefix : Boolean
       get() = number.startsWith("+")

}

Nie ma zbyt wiele kodu, ale za kulisami dzieje się wiele rzeczy. Przejdziemy przez to krok po kroku. Przede wszystkim stworzyliśmy ogólnodostępną klasę finałową Kontakt.

Jest to podstawowa zasada, z którą musimy się zmierzyć: jeśli nie określono inaczej, klasy są domyślnie publiczne i ostateczne (nawiasem mówiąc, to samo dotyczy metod klasowych). Jeśli chcesz dziedziczyć po klasie, zaznacz to słowem kluczowym open.

Pluton65
źródło
0

Oto praktyczny, rzeczywisty przykład metody pobierającej i ustawiającej Kotlin (zobacz więcej szczegółów tutaj ):

// Custom Getter
val friendlyDescription get(): String {
    val isNeighborhood = district != null
    var description = if (isNeighborhood) "Neighborhood" else "City"
    description += " in"
    if (isNeighborhood) {
        description += " $city,"
    }
    province?.let {
        if (it.isNotEmpty()) {
            description += " $it,"
        }
    }
    description += " $country"
    return description
}

print(myLocation.friendlyDescription) // "Neighborhood in Denver, Colorado, United States"


// Custom Setter
enum class SearchResultType {
    HISTORY, SAVED, BASIC
}

private lateinit var resultTypeString: String

var resultType: SearchResultType
    get() {
        return enumValueOf(resultTypeString)
    }
    set(value) {
        resultTypeString = value.toString()
    }

result.resultType = SearchResultType.HISTORY
print(result.resultTypeString) // "HISTORY"

Ricky Padilla
źródło