方法参数可以包含对其他变量的引用而不是包含值吗?
Posted
技术标签:
【中文标题】方法参数可以包含对其他变量的引用而不是包含值吗?【英文标题】:Can a method parameter contain a reference to other variable instead of containing a value? 【发布时间】:2022-01-21 02:43:29 【问题描述】:在下面的代码中,我想对其进行概括,以便我可以对 viewBinding.secondEditText.text
和 viewModel.property.income
使用相同的方法,而不是 viewBinding.editText.text
和 viewModel.property.price
。
我正在考虑用 viewBinding.editText.text
交换主构造函数中定义的变量,但我需要该变量包含对 viewBinding.editText.text
/viewBinding.secondEditText.text
等的引用,而不是包含值。
这可能吗?我已经查看了这方面的长度,但找不到任何有用的东西。
fun updateProperty()
//... other irrelevant code
if (viewBinding.editText.text.toString() != "")
viewModel.property.price = viewBinding.editText.text.toString().toDouble()
//... other irrelevant code
【问题讨论】:
通过传入引用和属性引用进行泛化是一种方法,但也许控制反转对于您的用例可能更方便?当案例难以概括时,当它们没有共同点时,IoC 会很方便。 【参考方案1】:您可以将参数传递给函数,是的!
这个比较简单:
fun updateProperty(editText: EditText)
val contents = editText.text.toString()
很简单,你只需传入EditText
的任何实例,函数就会对其进行处理。
如果你只是使用带有 setter 和 getter 的对象,你可以定义你将要使用的类型并将它们传递进来。根据 viewmodel.property
是什么,你可以将它传递为好吧,然后访问 price
和 income
就可以了。如果您要使用其他类型,则可以使用接口或密封类 - 如果您要使用适用于所有类型的通用函数,它们需要一些通用性。
属性有点复杂 - 假设 viewmodel.property
包含一个 var price: Double
,并且您不想传递 property
本身,只是一个存在于某处的 Double
,您可以这样做:
import kotlin.reflect.KMutableProperty0
var wow: Double = 1.2
fun main()
println(wow)
setVar(::wow, 6.9)
println(wow)
fun setVar(variable: KMutableProperty0<Double>, value: Double)
variable.set(value)
>> 1.2
>> 6.9
(如果您不熟悉 ::
语法,请参阅 Property references)
KMutableProperty0
表示对没有任何接收者的可变属性(var
)的引用——只是一个基本的 var。不要担心 reflect
导入,这是基本的反射东西,比如函数引用,它是基本 Kotlin 安装的一部分
【讨论】:
谢谢,我还没有尝试实现它,但我认为它会成功!不过后续问题:假设我想“传递属性本身”(如您所写)而不是特定的双精度,相同的通用解决方案(但稍作调整)是否就足够了? @zorigo 如果您的意思是viewmodel.property
,那么这是某种具有(至少)price
和income
字段的对象。如果它是一个类,并且您正在传递该类的各种实例,那么您可以将该类设置为参数的类型。如果有多个类(或匿名对象),但它们仍然有 price
和 income
字段,则可以将这些字段作为对象实现的接口的一部分,并将该接口设为参数类型。
@zorigo 如果您要传入具有不同字段的任意对象(因此您可能正在更新thing.income
,或者您可能正在更新thing.partyLevel
),那么您的函数将需要一些逻辑来计算你传入了哪些内容以及如何处理它,例如在when
块中。你要么需要定义一个包含所有允许传入的东西的类型,要么你的逻辑必须检查它确实处理的类型并忽略其余的。当然在这一点上它不是很普遍!属性引用方法不需要知道什么是什么【参考方案2】:
是的,方法参数也可以是对类或接口的引用。并且方法参数也可以是对其他方法/函数/lambdas的引用。
如果您要处理难以概括的情况,请考虑使用某种控制反转(函数作为参数或 lambda)。
向 updateProperty 函数添加 lambda 参数
fun updateProperty(onUpdate: (viewBinding: YourViewBindingType, viewModel: YourViewModelType) -> Unit)
//... other irrelevant code
// here you just call the lambda, with any parameters that might be useful 'on the other side'
onUpdate(viewBinding, viewModel)
//... other irrelevant code
代码中的其他地方 - 案例 1:
updateProperty() viewBinding, viewModel ->
if (viewBinding.editText.text.toString() != "")
viewModel.property.price = viewBinding.editText.text.toString().toDouble()
代码中的其他地方 - 案例 2:
updateProperty() viewBinding, viewModel ->
if (viewBinding.secondEditText.text.toString() != "")
viewModel.property.income = viewBinding.secondEditText.text.toString().toDouble()
代码中的其他地方 - 案例 3:
updateProperty() viewBinding, viewModel ->
// I am a totally different case, because I have to update two properties at once!
viewModel.property.somethingElse1 = viewBinding.thirdEditText.text.toString().toBoolean()
viewModel.property.somethingElse2 = viewBinding.fourthEditText.text
.toString().replaceAll("[- ]*", "").toInt()
然后您可以更进一步,为前两种情况定义一个函数,因为这两种情况可以泛化,然后在 lambda 中调用它(甚至将其作为 lambda 传递),这将为您节省一些代码,如果您在代码中的许多地方调用updateProperty()
,或者只是为它们中的每一个定义一个简单的函数,然后调用它,就像这样
fun updatePrice() = updateProperty() viewBinding, viewModel ->
if (viewBinding.editText.text.toString() != "")
viewModel.property.price = viewBinding.editText.text.toString().toDouble()
fun updateIncome() = updateProperty() viewBinding, viewModel ->
if (viewBinding.secondEditText.text.toString() != "")
viewModel.property.income = viewBinding.secondEditText.text.toString().toDouble()
然后在代码的其他地方你只需以非常简单的方式调用它
updatePrice()
updateIncome()
【讨论】:
以上是关于方法参数可以包含对其他变量的引用而不是包含值吗?的主要内容,如果未能解决你的问题,请参考以下文章