在将我的android项目从java翻译成Kotlin时,我遇到了Kotlin的一些问题 . 假设我有接口I和接口O,它扩展了接口I.
interface I{
}
interface O: I{
}
通用类A具有扩展interfaceI的泛型参数V,以及扩展类A的泛型类B:
abstract class A<V: I> {
}
class B : A<O>() {
}
当我试图创建这样的属性时:
val returnB: A<I>
get() = b
我收到编译错误'需要A,找到B' . 在Java中,这将没有任何问题 . 我如何使用Kotlin访问它?
我需要在我的应用程序中对Basic类使用这种方法 .
BaseViewModel,它具有Navigator类的通用参数:
abstract class BaseViewModel<N>(application: Application, val repositoryProvider:
RepositoryProvider) : AndroidViewModel(application) {
var navigator: N? = null
fun onDestroyView() {
navigator = null
}
open fun onViewAttached() {
}
}
BaseActivity类:
abstract class BaseActivity<T : ViewDataBinding, V : BaseViewModel<BaseNavigator>> : AppCompatActivity(),
BaseFragment.Callback, BaseNavigator {
// .......
private var mViewModel: V? = null
/**
* Override for set view model
* @return view model instance
*/
abstract val viewModel: V
// .......
}
BaseNavigator接口用于VM - View通信:
interface BaseNavigator {
fun invokeIntent(intent: Intent?, b: Bundle?, c: Class<*>?,
forResult: Boolean, requestCode: Int)
fun replaceFragment(fragment: Fragment, addToBackStack: Boolean)
fun showDialogFragment(fragment: DialogFragment?, tag: String?)
fun showToast(message: String?)
}
这里是我扩展这些类的示例代码:
AuthViewModel:
class AuthViewModel(context: Application, repositoryProvider: RepositoryProvider) :
BaseViewModel<AuthNavigator>(context,repositoryProvider) {
// ....
}
AuthNavigator:
interface AuthNavigator : BaseNavigator {
fun requestGoogleAuth(code: Int)
fun requestFacebookAuth(callback: FacebookCallback<LoginResult>)
}
和出现错误的AuthActivity类:
class AuthActivity : BaseActivity<ActivityAuthBinding, BaseViewModel<BaseNavagator>>(),
GoogleApiClient.OnConnectionFailedListener, AuthNavigator {
@Inject
lateinit var mViewModel: AuthViewModel
override val viewModel: BaseViewModel<BaseNavigator>
get() = mViewModel // Required:BaseViewModel<BaseNavigator> Found: AuthViewModel
}
我也尝试将AuthActivity中的泛型参数从BaseViewModel更改为AuthViewModel,但编译器抛出错误'required BaseViewModel' .
And i tried to change
override val viewModel: BaseViewModel<BaseNavigator>
get() = mViewModel
to
override val viewModel: AuthViewModel
get() = mViewModel
但在这种情况下编译器抛出错误'属性类型''AuthViewModel',这不是被覆盖的子类型' .
update: 当我向BaseViewModel添加属性时,这是有效的:
BaseViewModel<out N : BaseNavigator>
但在这种情况下我只能创造
private var navigator: N? = null
我需要公开,所以我可以在Activity类中设置它 . 我可以为这个属性创建公共setter吗?当我尝试创建setter时会发生错误:
private var navigator: N? = null
fun setNavigator(n: N) { // error: Type parameter N is declared as 'out' but occurs in 'in' position in type N
navigator = n
}
1 回答
看起来您期望type参数具有协变性 . Kotlin使用声明站点方差 . 如果未指定方差,则泛型类型参数是不变的 .
换句话说,现在
A<I>
和A<O>
之间没有任何关系 . 但是,如果你宣布那么
A<O>
是A<I>
的子类型 .(对于逆变,也有
<in>
,反之亦然 . 有关详细信息,请参阅https://kotlinlang.org/docs/reference/generics.html . )