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

Чтение книги онлайн.

Читать онлайн книгу Programming Kotlin Applications - Бретт Мак-Лахлин страница 20

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

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

that solution works, it's a bit inelegant. It is going to require every user of your 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.

      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:

      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.

      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

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