java - 为什么这不会重载?

标签 java kotlin overloading type-inference overload-resolution

写在 Jooq 助手类上。 (一旦我弄明白了,就会添加更多特定于业务的方法...)

import org.jooq.*
import org.springframework.stereotype.Repository
import javax.inject.Inject
import javax.inject.Provider

/**A helper class facilitating database manipulations.
 * Uses jOOQ for its manipulations.
 * Relies on the application context being properly initialized s.t. Spring creates and injects the correct
 * [DSLContext].*/
@Repository
class DatabaseManipulator{

    private val provider: Provider<DSLContext>
    private val create:DSLContext
        get() = provider.get()

    @Inject
    constructor(provider: Provider<DSLContext>) {
        this.provider = provider
    }


    /**Executes non-[Select]-type SQL queries on the database.
     * Does not perform any kind of checks and trusts the client to know what they're doing.
     * @param query the query to be executed.
     *
     * @return depending on the type of the [query]:
     *      <ul>
     *      <li> Delete : the number of deleted records</li>
     *      <li> Insert : the number of inserted records</li>
     *      <li> Merge : result may be meaningless</li>
     *      <li> Truncate : result may be meaningless</li>
     *      <li> Update : the number of updated records</li>
     *      </ul>
     */
    fun execute(query:DSLContext.()-> Query):Int{
        return create.query().execute()
    }

    /**Executes [Select]-type [query] and returns its result*/
    fun <T:Record> execute(query:DSLContext.()->Select<T>):Result<T>{
        return create.query().fetch()
    }
}

到目前为止,还不错。现在让我们添加一些测试

@RunWith(SpringJUnit4ClassRunner::class)
@SpringBootTest
@Transactional
class DatabaseManipulatorIT {

    @Inject
    private lateinit var manipulate:DatabaseManipulator

    @Inject
    private lateinit var em:EntityManager

    @Test
    fun executeSelectQuery() {
        //given
        val expectedNumberOfOrganizations = em.createQuery("SELECT COUNT (o) FROM Organization o")
            .singleResult as Long

        //when
        val reportedNumberOfOrganizations = manipulate.execute {
            selectCount().from(ORGANIZATION)
        }.first().value1().toLong()

        //then
        assertThat(reportedNumberOfOrganizations).isEqualTo(expectedNumberOfOrganizations)
    }

    @Test
    fun executeNonSelectQuery() {
        //given
        val expectedNumberOfDeletions = em.createQuery(
            "SELECT COUNT (o) FROM Organization o WHERE o.usageCreditLimited = true"
        ).singleResult as Long

        //when
        val actualNumberOfDeletions = manipulate.execute {(
            deleteFrom(ORGANIZATION)
                .where(ORGANIZATION.USAGECREDITLIMITED.eq(true))
            ) as Query
        }

        //then
        assertThat(actualNumberOfDeletions).isEqualTo(expectedNumberOfDeletions)

    }
}

编译失败是因为

Error:(50, 50) Kotlin: Type inference failed: fun <T : Record> execute(query: DSLContext.() -> Select<T>): Result<T>
cannot be applied to
(DSLContext.() -> DeleteConditionStep<OrganizationRecord!>!)
Error:(50, 58) Kotlin: Type mismatch: inferred type is DSLContext.() -> DeleteConditionStep<OrganizationRecord!>! but DSLContext.() -> Select<???> was expected

不废话,我不想你用那个方法,我想让你用其他

让我们试着明确一点:

//when
val actualNumberOfDeletions = manipulate.execute {(
    deleteFrom(ORGANIZATION)
        .where(ORGANIZATION.USAGECREDITLIMITED.eq(true))
    ) as Query
}

仍然无法编译第二个测试用例,因为

Error:(50, 50) Kotlin: Type inference failed: fun <T : Record> execute(query: DSLContext.() -> Select<T>): Result<T>
cannot be applied to
(DSLContext.() -> Query)
Error:(50, 58) Kotlin: Type mismatch: inferred type is DSLContext.() -> Query but DSLContext.() -> Select<???> was expected

如何让 Kotlin 调用正确的方法?

最佳答案

Select 本质上是 Query,因此无法正确推断您要使用的方法。

The compiler resolves everything about the method invocation without paying any attention to the generic constraints involved until the very last moment – where it notices that the chosen method isn’t valid, and fails with an error.

generics 会出现此问题,编译器将这些方法识别为两种不同的方法,但在尝试解析该方法时,它可能无法根据可用数据找到正确的方法。如果您想知道为什么查看这篇文章,Overloading and Generic constraints乔恩·斯基特 (Jon Skeet) 着。

关于java - 为什么这不会重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55829074/

相关文章:

java - 如何在按下时以编程方式更改按钮文本颜色?

java - 将 wav 文件切割成片段

json - 使用 kotlinx.serialization 将 json 对象属性反序列化为字符串

java - Kotlin 扩展冲突

postgresql - 是否可以使用子类型重载来配置函数?

java - 在单个 java 文件中使用两个 java 类的性能问题

java - 如何纠正 Native.loadlibrary 错误

json - Moshi 将 null 反序列化为空列表

c++ - 在 C++ 的编译过程中如何在内部表示重载函数

Java:Vector<derived> 可以被称为 Vector<base> 吗?