在不使用 kotlin-reflect 的情况下,如何获取对属性设置器的方法引用?
基本上,如果我用 java 方式编写代码,那就非常简单
fun setValue(i: Int) = Unit
val a: (Int) -> Unit = this::setValue
Run Code Online (Sandbox Code Playgroud)
但因为var value: Int我得到
var value = 1
val a: KMutableProperty0<Int> = this::value
Run Code Online (Sandbox Code Playgroud) 有没有办法在不指定所有属性的情况下合并 kotlin 数据类?
data class MyDataClass(val prop1: String, val prop2: Int, ...//many props)
Run Code Online (Sandbox Code Playgroud)
具有以下签名的函数:
fun merge(left: MyDataClass, right: MyDataClass): MyDataClass
Run Code Online (Sandbox Code Playgroud)
这个函数检查两个类的每个属性,它们不同的地方使用 left 参数来创建一个新的 MyDataClass。
使用 kotlin-reflect 或其他方法可以实现吗?
编辑:更清晰
这是我想要做的更好的描述
data class Bob(
val name: String?,
val age: Int?,
val remoteId: String?,
val id: String)
@Test
fun bob(){
val original = Bob(id = "local_id", name = null, age = null, remoteId = null)
val withName = original.copy(name = "Ben")
val withAge = original.copy(age = 1)
val withRemoteId = original.copy(remoteId = "remote_id") …Run Code Online (Sandbox Code Playgroud) 我正在试验Kotlin中的反射功能,但我似乎无法理解如何获取KType值.
假设我有一个将短语映射到对象工厂的类.在模糊的情况下,用户可以提供type将搜索范围缩小到仅返回该类型对象(或某些子类型)的工厂的参数.
fun mapToFactory(phrase: Phrase,
type: KType = Any::class): Any {...}
Run Code Online (Sandbox Code Playgroud)
type我需要接受几乎任何东西,包括Int从我的经验中看起来有点特别对待.默认情况下,它应该是类似的Any,这意味着"不排除任何工厂".
如何为默认值(或任何值)指定type?
我尝试使用默认参数值调用函数,而不在 Kotlin 中添加参数。
例如:
class Test {
fun callMeWithoutParams(value : Double = 0.5) = value * 0.5
fun callIt(name: String) = this.javaClass.kotlin
.members.first { it.name == name }
.callBy(emptyMap())
}
fun main(args: Array<String>) {
println(Test().callIt("callMeWithoutParams"))
}
Run Code Online (Sandbox Code Playgroud)
我有一个例外:
Exception in thread "main" java.lang.IllegalArgumentException: No argument provided for a required parameter: instance of fun
Test.callMeWithoutParams(kotlin.Double): kotlin.Double
at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod(KCallableImpl.kt:139)
at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:111)
at Test.callIt(Main.kt:15)
at MainKt.main(Main.kt:20)
Run Code Online (Sandbox Code Playgroud)
奇怪的是,该参数不是必需的,而是可选的......
我使用以下方法实例化我的对象:
val payInCurrency = Currency::class.createInstance()
.copy(code = "GBP")
Run Code Online (Sandbox Code Playgroud)
但我在那一行遇到了一个例外:
java.lang.IllegalArgumentException: Class should have a single no-arg constructor: class com.abc.Currency
at kotlin.reflect.full.KClasses.createInstance(KClasses.kt:281)
at com.abc.MyInteractorTest.setUp(MyInteractorTest.kt:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:106)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown …Run Code Online (Sandbox Code Playgroud) 我可以使用反射访问私有 val 值,如下所示
fun main() {
val mainClass = MainClass()
val f = MainClass::class.memberProperties.find { it.name == "info" }
f?.let {
it.isAccessible = true
val w = it.get(mainClass) as String
println(w)
}
}
class MainClass {
private val info: String = "Hello"
}
Run Code Online (Sandbox Code Playgroud)
但是如果我想改变info,我怎么能用反射来做呢?
我正在对Kotlin的反思进行一些实验.
我试图通过其参数获得泛型类的反射对象.
在Java中,那将是一个ParameterizedType.
使用Java的反射API获取此类内容的方法有点复杂:创建泛型类的匿名子类,然后获取其超类型的第一个参数.
这是一个例子:
@Suppress("unused") @PublishedApi
internal abstract class TypeReference<T> {}
inline fun <reified T> jGeneric() =
((object : TypeReference<T>() {}).javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
Run Code Online (Sandbox Code Playgroud)
当我println(jGeneric<List<String?>>())打印时java.util.List<? extends java.lang.String>,考虑到Kotlin List使用声明站点out方差并且Java类型没有可空性概念,这是合乎逻辑的.
现在,我希望获得相同类型的结果,但使用Kotlin反射API(当然,它包含可空性信息).
当然,List<String>::class因为它产生了一个不能工作KClass.我正在寻找一个KType.
但是,当我尝试这个:
inline fun <reified T> kGeneric() =
(object : TypeReference<T>() {})::class.supertypes[0].arguments[0].type
Run Code Online (Sandbox Code Playgroud)
当我println(kGeneric<List<String?>>()),它打印[ERROR : Unknown type parameter 0],这是相当......好吧,虎头蛇尾;)
在Kotlin,我怎样才能得到一个KType反映List<String>?
将尽可能简洁地保持这个......
我想在我的MainActivty类中有一个方法,比如updateUI().
我有另一个文件是一个名为FBManager的对象.该对象基本上拥有"静态"firebase访问方法..让我们说signInUser()
从Activity我调用FBManager.signInUser()...它做了一些逻辑并通过2个私有方法移动,在最后一个私有方法中,我想基本上调用MainActivity.updateUI()...
这不能完成,因为kotlin没有静态方法,并且不能使updateUI()静态.MainActivity().updateUI()编译但不正确,并且不想实例化新的MainActivity.最后,我想把活动传递给第一个构造函数,比如FBManager.signInUser(this)......但是在signInUser()之后,它会转到一个覆盖方法,它只能将一个包作为一个可选输入(我不是相信你可以把活动放到一个包中),因此我无法将活动引用传递给最终的私有方法.....
编辑:进一步阐述
object FBManager {
fun signInUser() {
// Create intent
startActivityForResult(intent)
}
override fun onActivityResult(some intent stuff) {
//Try catch block. In try block call
firebaseAuth(Google account)
}
fun firebaseAuth(acct: GoogleSignInAccount) {
//More logic and an .onCompleteListener
// Inside .onCompeteListener, which is the problem....
MainActivity.updateUI()
}
}
Run Code Online (Sandbox Code Playgroud)
为布局道歉......在我的手机上打字......
- 编辑 -
我希望所有这些都有意义,因为我是编程新手,并且发现很难解释我的问题(因为如果我真的理解它们,我可以想出一个解决方案......)
那么根据标题,还有其他方法可以做到这一点......从一个对象FBManager调用MainActivity中的方法吗?
我正在尝试String?在Kotlin反射练习中匹配nullable的类型:
data class Test(a: String, b: String?)
val test = Test("1", "2")
val properties = test::class.declaredMemberProperties
val propertyNames = properties.joinToString(",") {
when (it.returnType) {
String?::class.createType() -> "string?"
String::class.createType() -> "string"
else -> throw Exception()
}
}
Run Code Online (Sandbox Code Playgroud)
唉,它与错误而失败,Type in a class literal must not be nullable为String?::class。