Kotlin 可以动态为对象绑定一个额外对象吗?

pdog
  • 573

我有一个方法,每次都必须传入一个固定的对象 paint,因为这个函数会被频繁调用,所以我不能在内联函数中创建对象。

inline fun Canvas.drawPoint(
    point: PointF,
    paint: Paint) {

    drawPoint(point.x, point.y, paint)
}

但是我很多地方都会调用这个方法。

          //(Canvas.apply(..,..))
            drawPoint(pointA, pointPaint)
            drawPoint(pointB, pointPaint)
            drawPoint(pointC, pointPaint)
            drawPoint(pointD, pointPaint)

可以看到每次都会传入一个pointPaint对象。
所以我在想有没有类似这样一个功能

        //(Canvas.apply(..,..))
            bind(pointPaint)
            drawPoint(pointA)
            drawPoint(pointB)
            drawPoint(pointC)
            drawPoint(pointD)
回复
阅读 1.7k
2 个回答
twiceyuan
  • 473
✓ 已被采纳

完美符合你要求的方式肯定是没有的,因为 bind 函数不可能改变另一个函数内部的局部变量。

折中的方式也有很多,比如定义一个包级属性:

var drawPaint: Paint? = null

然后原来的函数改为:

inline fun Canvas.drawPoint(
    point: PointF,
    paint: Paint) {

    paint?.let {
        drawPoint(point.x, point.y, it)
    }
}

方便使用还可以再定义一个函数来确保 drawPaint 能被准确的赋值和释放:

fun bindPaint(paint: Paint, action: () -> Unit) {
    drawPaint = paint
    action()
    drawPaint = null
}

这样使用时就是:

// Canvas().apply {
bindPaint(somePaint) {
    drawPoint(x, y)
}

还有一种方式是定义一个包装类,并在其中定义一个包含带接收者 Lambda 表达式的参数的函数(接收者为 Canvas),然后将扩展函数定义到这个类中:

class PointPainter(private val paint: Paint) {
    fun Canvas.drawPoint(rect: RectF) {
        drawPoint(rect.x, rect.y, paint)
    }
}

然后定义含有接收者为这个包装对象 Lambda 参数的函数:

fun bindPointPainter(paint: Paint, drawAction: PointPainter.() -> Unit) {
    PointPainter(paint).drawAction()
}

这样用时更方便一些:

// in canvas.apply block
bindPointPainter(somePaint) {
    drawPoint(rect1)
    drawPoint(rect2)
    // ...
}
    fun test() {
        Canvas().bindPaintDrawPoints(Paint())(
            arrayOf(PointF(1f, 2f),
                PointF(2f, 2f),
                PointF(3f, 2f),
                PointF(4f, 2f))
        )
    }

    fun Canvas.bindPaintDrawPoints(paint: Paint): (Array<PointF>) -> Unit {
        return {
            drawPoints(paint, it)
        }
    }

    fun Canvas.drawPoints(paint: Paint, points: Array<PointF>) {
        for (p in points) {
            this.drawPoint(p.x, p.y, paint)
        }
    }

宣传栏