The Code B is a class, but I can't understand the Code B fully.
I can use the class NewCoordinate
in Code A.
Can you write a the same function as Code A without using .run{..}
or .wth{..}
?
Code A
fun doTo(){
val mCoordinate = NewCoordinate(2.0f, 3.0f)
mCoordinate.run {
var mPoint =3.0f.toX
}
with(mCoordinate){
var mPoint =3.0f.toX
}
}
Code B
class NewCoordinate(private val xOrigin: Float, private val yOrigin: Float) {
val Float.toX: Float get() = xOrigin this
val Float.toY: Float get() = yOrigin - this
}
Added Content
To cactustictacs: Thanks!
In Code C, I have added a extension function .ext
for the class NewCoordinate
, it wrapped with .run {...}
.
But I still get the wrong, why?
Code C
fun doTo() {
val mCoordinate = NewCoordinate(2.0f, 3.0f)
mCoordinate.ext {
var mPoint =3.0f.toX //It's wrong
}
}
fun NewCoordinate.ext(block: ()->Unit){
this.run {
block()
}
}
class NewCoordinate(private val xOrigin: Float, private val yOrigin: Float) {
val Float.toX: Float get() = xOrigin this
val Float.toY: Float get() = yOrigin - this
}
Added Content Again
The Code D is answer based by cactustictacs's thinking. It's great, thanks again.
Code D
fun drawDial(drawScope: DrawScope){
val mCoordinate = NewCoordinate(drawScope.size.width / 2.0f, drawScope.size.height / 2.0f)
mCoordinate.draw(drawScope){
it.drawCircle(Offset(x = 0.0f.toX, y = 0f.toY), Radius, paintDial)
}
}
fun NewCoordinate.draw(drawScope: DrawScope, block: NewCoordinate.(canvas: Canvas) -> Unit ){
drawScope.drawIntoCanvas{
block(it)
}
}
class NewCoordinate(private val xOrigin: Float, private val yOrigin: Float) {
val Float.toX: Float get() = xOrigin this
val Float.toY: Float get() = yOrigin - this
}
CodePudding user response:
This:
val Float.toX: Float get() = xOrigin this
is an extension property. It allows you to "add" a property to a class (in this case the Float
class) without needing to modify the source of that class. So when that extension property is in scope (where the code you're running can "see" it) you can call toX
on any Float
, and it'll run that code.
If an extension is declared at the top level of the current file, anything in that file can access it - it's in scope. If it's at the top level of another file, and visibility modifiers allow it, you can import
it - now it's in scope.
But if it's declared inside a class, only code inside that class (or its subclasses) can see it - it's not accessible from the outside. (If you look at the link up there, and scroll down to the Declaring extensions as members section, you can see an example where they explicitly demonstrate this)
So that's a problem - but what receiver-style scope functions like run
, apply
and with
do is allow you to run code "inside" the object you're calling them on. It's as if your code is part of the object's class - and that means those Float
extension properties are now in scope, and you can use them!
This doesn't allow you to get around visibility modifiers - if you make those properties private
in NewCoordinate
, you won't be able to access them. If you like, run
is a bit like an extension function on NewCoordinate
- you can "add" functionality that behaves as though it's part of the class's code, which makes use of stuff that's publicly accessible on the class.
It's shifting your point of reference, so you can access things more easily - but nothing that you couldn't access before! It's just that in this case, the language didn't allow you to reference Float.toX
from outside the scope - the property is still public, but right now there's no way to say mCoordinate::toX
or mCoordinate::Float::toX
or anything like that. You have to put yourself in scope so you can call it the usual way!