Kotlin 泛型属性问题

Kotlin generic properties issue

在将我的 android 项目从 java 转换为 Kotlin 时,我遇到了一些 Kotlin 问题。 假设我有接口 I 和扩展接口 I 的接口 O。

interface I{

}

interface O: I{

}

和泛型 class A 具有扩展接口 I 的泛型参数 V,以及扩展 class A:

的泛型 class B
abstract class A<V: I> {

}

class B : A<O>() {

}

当我尝试创建这样的 属性:

val returnB: A<I>
    get() = b

我遇到编译器错误 'required A, found B'。在 Java 中,这将毫无问题地工作。我如何使用 Kotlin 访问它?

我需要在我的应用程序中对 Basic classes 使用这种方法。

具有 Navigator 通用参数的 BaseViewModel class:

abstract class BaseViewModel<N>(application: Application, val repositoryProvider:
RepositoryProvider) : AndroidViewModel(application) {

    var navigator: N? = null

    fun onDestroyView() {
        navigator = null
    }

    open fun onViewAttached() {

    }
}

基础Activity class:

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 - 查看通信:

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?)
}

这里是我扩展这些 classes:

的示例代码

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出现错误的地方:

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

但在这种情况下编译器会抛出错误“属性 type is 'AuthViewModel', which is not a subtype type of overridden'.

更新: 当我将 属性 添加到 BaseViewModel:

时有效
BaseViewModel<out N : BaseNavigator>

但在这种情况下我只能创建

private var navigator: N? = null

我需要 public 这样我就可以在 Activity class 中设置它。我可以为这个 属性 创建 public 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
}

您似乎希望类型参数表现得协变。 Kotlin 使用声明站点变量。如果不指定方差,泛型类型参数是invariant.

也就是说,现在A<I>A<O>之间没有关系。但是如果你声明

abstract class A<out V : I>

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

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