类型推断失败:没有足够的信息来推断参数请明确指定它

Jen*_*ger 5 data-binding type-inference vaadin kotlin

我正在尝试在Kotlin写一个Vaadin应用程序.对于数据绑定,Vaadin 8现在提供了类型安全数据绑定的可能性.在Kotlin我会期待这样的工作:

class LoginModel {
    var username: String = ""
    var password: String = ""
}

class LoginView : FormLayout() {
  val name = TextField("name")
  val password = TextField("password")
  val loginButton = Button("login")

  init {
      val binder = Binder<LoginModel>()
      binder.forField(name).bind(
          { it.username }, 
          { bean, value -> bean.username = value })

     //... 
  }
}
Run Code Online (Sandbox Code Playgroud)

我在这里收到以下错误消息:

Error:(23, 31) Kotlin: Type inference failed: Not enough information to infer parameter BEAN in fun <BEAN : Any!, TARGET : Any!, BEAN : Any!> Binder.BindingBuilder<BEAN#1 (type parameter of bind), TARGET>.bind(p0: ((BEAN#1!) -> TARGET!)!, p1: ((BEAN#1!, TARGET!) -> Unit)!): Binder.Binding<BEAN#1!, TARGET!>!
Please specify it explicitly.
Run Code Online (Sandbox Code Playgroud)

我尝试通过显式指定类型参数:

binder.forField(name).bind<LoginView, String, LoginView>(
    { it.username }, 
    { bean, value -> bean.username = value })
Run Code Online (Sandbox Code Playgroud)

但这导致错误信息(和其他sytax错误,所以我没有遵循这种方法)

Error:(23, 35) Kotlin: No type arguments expected for fun bind(p0: ValueProvider<LoginModel!, String!>!, p1: Setter<LoginModel!, String!>!): Binder.Binding<LoginModel!, String!>! defined in com.vaadin.data.Binder.BindingBuilder
Run Code Online (Sandbox Code Playgroud)

我的第二种方法是尝试直接传递Kotlin属性访问器,但错误消息与第一个相同:

binder.forField(name).bind(LoginModel::username.getter, LoginModel::username.setter)
Run Code Online (Sandbox Code Playgroud)

最后一个尝试是尝试使用扩展方法并使所有内容尽可能明确:

fun <BEAN, TARGET> Binder.BindingBuilder<BEAN, TARGET>.bind(property: KMutableProperty1<BEAN, TARGET>) {

    fun set(bean: BEAN): TARGET = property.get(bean)
    fun get(bean: BEAN, value: TARGET): Unit = property.set(bean, value)
    this.bind(::set, ::get)
}
Run Code Online (Sandbox Code Playgroud)

但它仍然导致与第一个相同的错误消息

Mar*_*sny 3

我已经尝试过你的示例,它在我的 Intellij 2017.1.4 和 Kotlin 1.1.2-5 上编译得很好。也许您在旧版本的 Kotlin 插件中发现了一个错误?

该方法bind不采用泛型参数,因此无法泛化。该forField方法采用一个通用参数,所以也许你可以尝试

    binder.forField<String>(name).bind(
            { it.username },
            { bean, value -> bean.username = value })
Run Code Online (Sandbox Code Playgroud)

但首先,请确保您拥有最新版本的 Kotlin 插件,和/或尝试使用 Intellij 社区版。

不过,我强烈建议您使用,bind(String)因为其他绑定方法不适用于 JSR303 验证。您还可以定义以下扩展方法:

fun <BEAN, FIELDVALUE> Binder.BindingBuilder<BEAN, FIELDVALUE>.bind(prop: KMutableProperty1<BEAN, FIELDVALUE?>): Binder.Binding<BEAN, FIELDVALUE> =
        bind(prop.name)
Run Code Online (Sandbox Code Playgroud)

并从您的代码中按如下方式调用它binder.forField(name).bind(LoginModel::username)。请参阅此处了解更多示例:https://github.com/mvysny/karibu-dsl/blob/master/example-v8/src/main/kotlin/com/github/vok/karibudsl/example/form/FormView.kt