首页 文章

Kotlin通用属性问题

提问于
浏览
1

在将我的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 回答

  • 2

    看起来您期望type参数具有协变性 . Kotlin使用声明站点方差 . 如果未指定方差,则泛型类型参数是不变的 .

    换句话说,现在 A<I>A<O> 之间没有任何关系 . 但是,如果你宣布

    abstract class A<out V : I>
    

    那么 A<O>A<I> 的子类型 .

    (对于逆变,也有 <in> ,反之亦然 . 有关详细信息,请参阅https://kotlinlang.org/docs/reference/generics.html . )

相关问题