【问题标题】:In the code, the type of the lambda is mismatched, how does it work?在代码中,lambda的类型不匹配,它是如何工作的?
【发布时间】:2021-10-18 20:25:26
【问题描述】:

我在Android 上使用Epoxy library

我很好奇的是为什么lambda expressionparameter在类型不匹配时不会出错。

listener 是一个 lambda expression,它采用 Int type 作为参数。

但是listener(addDetailClicked)工作正常。

不应该是listener(Int)吗?或listener({ i -> addDetailClicked(i) })

其实我写了代码也不知道为什么会这样。

这怎么可能?

型号

@EpoxyModelClass(layout = R.layout.item_routine)
abstract class EpoxyRoutineModel() : EpoxyModelWithHolder<EpoxyRoutineModel.Holder>() {
    @EpoxyAttribute
    var workout: String = "see"

    @EpoxyAttribute
    var curPos: Int = 0

    @EpoxyAttribute
    lateinit var listener: (Int) -> Unit // this

    override fun bind(holder: Holder) {
        holder.workout.text = workout
        holder.add_btn.setOnClickListener {
            listener(curPos)
        }
    }
}

控制器

class RoutineItemController(
    private val addDetailClicked: (Int) -> Unit)
    : EpoxyController() {
    private var routineItem : List<RoutineItem>? = emptyList()

    override fun buildModels() {
        var i:Int =0
        routineItem?.forEach {
            when(it) {
               is RoutineItem.RoutineModel ->
                   EpoxyRoutineModel_()
                       .id(i++)
                       .curPos(i++)
                       .workout("d")
                       .listener(addDetailClicked) // why? listener(Int) or listener({ i -> addDetailClicked(i) })
                       .addTo(this)
           }

        }
    }
}

片段

class WriteRoutineFragment : Fragment() {
    private var _binding : FragmentWriteRoutineBinding? = null
    private val binding get() = _binding!!
    private lateinit var epoxyController : RoutineItemController
    private val vm : WriteRoutineViewModel by viewModels { WriteRoutineViewModelFactory() }

    override fun onCreateView(inflater: LayoutInflater,
                              container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        _binding = FragmentWriteRoutineBinding.inflate(inflater, container, false)

        epoxyController = RoutineItemController(::addDetail)
        binding.rv.adapter = epoxyController.adapter
        binding.rv.itemAnimator = null

        return binding.root

    }
    private fun addDetail(pos: Int) {
        vm.addDetail2(pos)
    }
}

【问题讨论】:

    标签: android kotlin epoxy


    【解决方案1】:

    我相信您错过了EpoxyRoutineModel_ 包含EpoxyRoutineModel 中的数据类型的设置器这一事实。例如,EpoxyRoutineModel.curPos 的类型为 Int,因此 EpoxyRoutineModel_.curPos() 是一个声明为的函数:

    fun curPos(Int): EpoxyRoutineModel_
    

    (或类似的)

    同样,EpoxyRoutineModel.listener 的类型为 (Int) -&gt; Unit,因此 EpoxyRoutineModel_.listener() 声明为:

    fun listener((Int) -> Unit): EpoxyRoutineModel_
    

    所以listener() 是一个接收另一个函数的函数(它本身接收Int)。所以我们可以在那里提供addDetailClicked

    【讨论】:

    • 那你是说它和Java's user.setcurPos()user.setName()user.setNumber() 等...?
    • 我没有EpoxyRoutineModel_的代码,但好像有。例如,curPos(i++) 清楚地表明curPos() 是一个接收Int 的函数,所以它看起来像是某种setter。
    • 所以,listener(addDetailClicked) 可能的原因是listener() 不是将Int 作为parameter 的函数调用,而是简单地调用@987654346 的settter function @初始化listener property?那么,是否可以将(Int) -&gt; Unit 中的addDetailClickedlistener property 的类型对应为argument
    • 看起来是这样,是的。如果curPos()Int 的setter,那么同样,location() 应该是(Int) -&gt; Unit 函数的setter。这实际上是有道理的,因为您使用EpoxyRoutineModel_ 来构建EpoxyRoutineModel。后者包含(Int) -&gt; Unit 函数的属性,因此构建器必须提供一种设置方法。
    • 您应该可以 ctrl+单击.listener(addDetailClicked)。我猜你会看到这样声明的函数:fun listener((Int) -&gt; Unit): EpoxyRoutineModel_。这将确认这个函数实际上接收了另一个函数。
    猜你喜欢
    • 2016-12-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多