preface

When writing custom controls, you sometimes need to perform operations on the PointF object to calculate the horizontal and vertical spacing between two points.

Simplifying the requirement is all about figuring out the difference between the two points.

The code implementation looks something like this

fun minusPoint(p1: PointF, p2: PointF): Return PointF(dx, dy) {val p = minusPoint(p1,p2)}Copy the code

First Modification

This is way too Java, because we’re using Kotlin, so we can do this instead

Fun minusPoint(p1: PointF, p2: PointF): PointF = PointF(p1.x-p2.x, p1.y-p2.y)Copy the code

Second Modification

Of course, that’s not good enough. We use Kotlin’s extension function to add an extension function to the PointF object

Funtf.minuspoint (p2: PointF): PointF = PointF(this.x-p2.x, this.y-p2.y) // Use val p = p1.minuspoint (p2)Copy the code

Such calls look much more readable.

Third Revision

Because PointF comes with an offset method

public final void offset(float dx, float dy) {
  x += dx;
  y += dy;
}
Copy the code

So we can change it to something like this

Funtf.minuspoint (p2: PointF): PointF = PointF().apply {this.offset(-p2.x, -p2.y)} // use val p = p1.minuspoint (p2)Copy the code

Fourth Modification

For those of you with programming experience, one of the “problems” with this function is that it creates a new PointF object every time. So we can optimize it again.

Fun pointf.minusPoint (p2: PointF): PointF = this.apply {this.offset(-p2.x, -p2.y)}Copy the code

This way, no new object is created for each call, and the original object is used. Everything looks wonderful.

Fifth Revision

Let’s go back to where we started, and the problem we started with was “compute the difference between two points,” so semantically speaking. Is it possible to simply describe it like this

val p1: Point
val p2: Point
val p = p1 - p2 
Copy the code

Those of you who know Kotlin’s operator probably thought of the – operator from the first time you saw the requirement.

The PointF extension operator is obviously in KTX.

/** * Offsets this point by the negation of the specified point and returns the result * as a new point. */ inline Operator fun pointf. minus(p: PointF): PointF {return PointF(x, y). Apply {offset(-p.x, -p.y)}} // Use val p = p1-p2Copy the code

Once again sweet by Kotlin!

Sixth Revision

Observant friends will notice that this extension operator returns a new object each time.

Is KTX a bad function?

That’s not the case. Now back to our fourth “optimization.”

Fun pointf.minusPoint (p2: PointF): PointF = this.apply {this.offset(-p2.x, -p2.y)}Copy the code

Now let’s consider a problem where we take p1 and subtract p2 to get an object P, where P is actually P1, and their properties have been changed. If p1 is then used to do some other operations, obviously the result is not the same as expected.

See what the problem is? Our optimization “subtraction” changes the minuend, which is obviously unreasonable.

So our fifth modification is not reasonable, but I do not want to use the sixth scheme, because it does have extra objects, I would starve to death, die outside, will not eat this grammar sugar? ! .

So what should be done?

We said that a subtraction should not change the minuend, and that the subtraction should be a new value.

So is that all we have to do? Of course not. Let’s go back to our requirement, “Get the difference between two points.” This requirement could have been modified a little bit more: “Get the difference between two points.

So here we see that we have a very suitable operator to describe it, which is -=

Go straight to the code

MinusAssign (p: PointF) {this.apply {offset(-p.x, -p.y)}} // Inline operator fun pointf.minusassign (p: PointF) {this.apply {offset(-p.x, -p.y)}} // Use, no return value p -= p2Copy the code

BTW, inline is redundant because the argument passed is not a function type.

Since there is no return value, we can call it this way

val p1 = p.apply {
    this -= center
}
Copy the code

So we’re done subtracting.

What do I get by subtracting?

  • You know kotlin’s operator notation
  • You learned about some of Kotlin’s inline rules
  • If a function modifies the parameters passed in, you need to be careful whether you really should do so.