Название: Programming Kotlin Applications
Автор: Бретт Мак-Лахлин
Издательство: John Wiley & Sons Limited
Жанр: Программы
isbn: 9781119696216
isbn:
Person
class—you included—to add that F
to decimals or to use the Float
type for variables passed into a constructor. And, as you just learned, Kotlin uses Double
as the default decimal type.
A better solution is to realize that if Kotlin defaults to Double
, maybe you should, too. (At least, unless you have a really good reason not to.) So change your Person
constructor to take in what most users will pass—a Double
created from a typed-in number:
class Person(var firstName: String, var lastName: String, var height: Double, var age: Int, var hasPartner: Boolean) {
Easy enough! And, because you've anticipated how users will create a new instance of Person
, you'll annoy your friendly developer comrades a lot less.
NOTE Don't forget to remove the F
from the two numbers in your main
function. If you don't, you'll get another error—this time from trying to pass a Float
into a constructor that expects a Double
.
It's Easy to Break Kotlin (Sort of)
The title of this chapter is “It's Hard to Break Kotlin,” which may seem like the opposite of what you're seeing. Without much effort, you've managed to get Kotlin to throw a lot of different errors, and Kotlin seems quite resistant to helping you out with converting between types.
That said, Kotlin is actually breaking before your code is running in some production system, serving an API for a mobile app, or running on a phone or just handling web requests. In other words, Kotlin is making you do some extra work at compile time—when you're writing code—to avoid potential problems when the program is running and needs to work.
Put another way, the chapter might be better titled, “It's Hard to Break Kotlin When It's Running in Production Because It's Going to Make You Be Really Specific about Types When You're Writing that Code Before It Gets to Production.” Of course, that's really not a title that anyone is going to let get through editing and proofing, so let's go with “It's Hard to Break Kotlin” and trust that you know what that really means.
OVERRIDING PROPERTY ACCESSORS AND MUTATORS
With what you know about types, and strong types in particular, you're finally ready to get back to that annoying little detail of Person
: if you set the last name outside the Person
constructor, printing the class instance gives the original last name, not the modified one. As a refresher, here's the code in question:
// Create another person val rose = Person("Rose", "Bushnell", 56.8, 32, true) println(rose) // Change Rose's last name rose.lastName = "Bushnell-Truesby" println(rose)
The result? This:
Rose Bushnell Rose Bushnell
What really needs to happen here? Well, every time that a last name—or first name, for that matter—is updated, the full name of the person that the instance represents needs to be updated. Seems simple enough, right?
Well, hold on, because this is going to get fairly complicated really fast. You're about to enter the somewhat unusual world of overriding mutators and accessors in Kotlin.
Custom-Set Properties Can't Be in a Primary Constructor
What a mouthful! It's true, though: because we want to take control of what happens when a first or last name is changed, we're going to have to make a lot of changes to how Person
is constructed. Basically, we have to override the accessor for firstName
and lastName
. To do that, we cannot have those properties initialized in the Person
primary constructor.
NOTE You may have noticed the term “primary constructor” here. Think of that simply as “the constructor” for now. Later, you'll see that Kotlin lets you define multiple constructors, and the primary one is the one defined on the first line of the class—the one you already have.
More on this later, though, so don't worry too much about primary and secondary constructors for now.
Move Properties Out of Your Primary Constructors
You've actually just stumbled onto a fairly standard best practice in Kotlin: it's often a good idea to move property definitions out of the primary constructor. You'll recall that you started like this way back in Chapter 1:
class Person(firstName: String, lastName: String) {
Then, before you added other properties, you added the var
keyword to each listed data input:
class Person(var firstName: String, var lastName: String) {
This made firstName
and lastName
properties, with automatically generated accessors and mutators. The problem is that, while expedient at the time, this has now come back to bite you.
To undo this, simply remove var
from all of the properties in the current version of the Person
constructor:
class Person(firstName: String, lastName: String, height: Double, age: Int, hasPartner: Boolean) {
Now try to run your PersonApp
, and you're going to see an error discussed earlier:
Error:(13, 10) Kotlin: Unresolved reference: lastName
You should recall that because lastName
is not a property anymore (because there's no var
or val
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 СКАЧАТЬ