Programming Kotlin Applications. Бретт Мак-Лахлин

Programming Kotlin Applications - Бретт Мак-Лахлин


Скачать книгу
keyword in the constructor definition), Kotlin does not create accessors or mutators. That means that this line in main now won't work:

      rose.lastName = "Bushnell-Truesby"

      So there's a bit of an apparent conflict that has arisen:

       You can't customize accessors or mutators if a property is declared in a class's constructor.

       If a property isn't declared in a class's constructor, and it's not declared elsewhere in the class, you don't get an automatic accessor or mutator.

      Initialize Properties Immediately

      Now, just to make this a bit more complicated, there's another rule you've run across, too:

       Any property not defined in a constructor must be initialized on instance creation.

      To remember how this shows up, go ahead and define all the properties declared in your constructor, but this time do it just under the constructor line, similar to how you defined lastName :

      class Person(firstName: String, lastName: String, height: Double, age: Int, hasPartner: Boolean) { var fullName: String var firstName: String var lastName: String var height: Double var age: Int var hasPartner: Boolean // Set the full name when creating an instance init { fullName = "$firstName $lastName" }

      Compile, run, and you'll get another error you've seen before, but this time with all of your properties:

      Error:(6, 5) Kotlin: Property must be initialized or be abstract Error:(7, 5) Kotlin: Property must be initialized or be abstract Error:(8, 5) Kotlin: Property must be initialized or be abstract Error:(9, 5) Kotlin: Property must be initialized or be abstract Error:(10, 5) Kotlin: Property must be initialized or be abstract

      NOTE If that sentence seemed confusing, you're in good company. Two firstName pieces of information are floating around here: the one passed into the constructor, and the property name. That's a problem we'll fix shortly.

      package org.wiley.kotlin.person class Person(firstName: String, lastName: String, height: Double, age: Int, hasPartner: Boolean) { var fullName: String var firstName: String = firstName var lastName: String = lastName var height: Double = height var age: Int = age var hasPartner: Boolean = hasPartner // Set the full name when creating an instance init { fullName = "$firstName $lastName" } override fun toString(): String { return fullName } }

      Take just the line dealing with firstName :

      var firstName: String = firstName

      A property is declared, and it's both read and write, because var is used. (Remember, if you wanted this to be a read-only property, you'd use val.) That property is given a name— firstName—and then a type, String. Then, the new property is assigned a value. In this case, that value is whatever is passed into the constructor through firstName.

      You can now compile your code and run it, and it works again! (Although there's still that last name issue to fix. But you're getting closer.)

      Try to Avoid Overusing Names

      package org.wiley.kotlin.person class Person(_firstName: String, _lastName: String, _height: Double, _age: Int, _hasPartner: Boolean) { var fullName: String var firstName: String = _firstName var lastName: String = _lastName var height: Double = _height var age: Int = _age var hasPartner: Boolean = _hasPartner // Set the full name when creating an instance init { fullName = "$firstName $lastName" } override fun toString(): String { return fullName } }

      NOTE Because Kotlin is so strongly typed and has such unique functionality—multiple constructors, properties versus method inputs, and more—using these coding best practices will really help separate your code from the code of those who are less experienced and savvy.

      Override Mutators for Certain Properties

      You're now finally ready to do what we set out to do: override how changing a first name or last name works. First, you need to see how a typical mutator is defined.

      Here's some more rather Kotlin-specific code that defines a custom mutator; in this case, it's for firstName :

      var firstName: String = _firstName set(value) { field = value }

      WARNING Kotlin uses a property's definition line in a file to determine that, if there's a custom mutator (or accessor), that definition is on the very next line. That's a big deal, and worth noting.

      Then, value represents the value coming into the mutator. So in the following example, value would come to the firstName mutator as “Bobby”:

      // Change Brian's first name brian.firstName = "Bobby"

      Now here's where things look a little odd. There's this line:

      field = value

      What's going on there? What the heck is field ? Well, it's the property being mutated. It's what's called a backing field. So here, field references the backing field for the property, which is firstName (because that's the property just defined). That backing field is


Скачать книгу