kotlin - 如果带注释的成员没有被特定 block 包围,则发出 IDE 警告

标签 kotlin intellij-idea

我有一个数据结构,其中的成员不是线程安全的,调用者需要锁定资源以进行适当的读写。这是一个最小的代码示例:

class ExampleResource : LockableProjectItem {
    override val readWriteLock: ReadWriteLock = ReentrantReadWriteLock()

    @RequiresReadLock
    val nonThreadSafeMember: String = ""
}

interface LockableProjectItem {
    val readWriteLock: ReadWriteLock
}

fun <T : LockableProjectItem, Out> T.readLock(block: T.() -> Out): Out {
    try {
        readWriteLock.readLock().lock()
        return block(this)
    } finally {
        readWriteLock.readLock().unlock()
    }
}

fun <T : LockableProjectItem, Out> T.writeLock(block: T.() -> Out): Out {
    try {
        readWriteLock.writeLock().lock()
        return block(this)
    } finally {
        readWriteLock.writeLock().unlock()
    }
}

annotation class RequiresReadLock

调用 ExampleResource.nonThreadSafeMember 可能如下所示:

val resource = ExampleResource()
val readResult = resource.readLock { nonThreadSafeMember }

为了确保调用者知道需要锁定资源,我希望 IDE 对任何用 @RequiresReadLock 注解且未用readLock block 。有没有办法在 IntelliJ 中执行此操作,而无需为 IDE 编写自定义插件?

最佳答案

我认为这是一种黑客攻击,但使用 context receivers可能会起作用。但我认为它们不打算以这种方式使用。

您可以声明一个虚拟人 object充当上下文接收器,并将其作为上下文接收器添加到属性中:

object ReadLock

class ExampleResource : LockableProjectItem {
    override val readWriteLock: ReadWriteLock = ReentrantReadWriteLock()

    // properties with context receivers cannot have a backing field, so we need to explicitly declare this
    private val nonThreadSafeMemberField: String = ""

    context(ReadLock)
    val nonThreadSafeMember: String
        get() = nonThreadSafeMemberField
}

然后在 readLock ,您通过 object :

fun <T : LockableProjectItem, Out> T.readLock(block: context(ReadLock) T.() -> Out): Out {
    try {
        readWriteLock.readLock().lock()
        return block(ReadLock, this)
    } finally {
        readWriteLock.readLock().unlock()
    }
}

注释:

  • 如果您尝试访问nonThreadSafeMember,则会出现错误没有上下文接收器:

    val resource = ExampleResource()
    val readResult = resource.nonThreadSafeMember //error
    
  • 您仍然可以访问nonThreadSafeMember无需通过执行例如操作来获取读锁

    with(ReadLock) { // with(ReadLock) doesn't acquire the lock, just gets the context receiver
        resource.nonThreadSafeMember // no error
    }
    

    但是不小心写出这样的东西要困难得多,我认为这正是你想要阻止的。

  • 如果你调用 readLock 内的另一个函数,并且您想要访问nonThreadSafeMember在该函数内,您应该用 context(ReadLock) 标记该函数也。例如

    fun main() {
        val resource = ExampleResource()
        val readResult = resource.readLock {
            foo(this)
        }
    }
    
    context(ReadLock)
    fun foo(x: ExampleResource) {
        x.nonThreadSafeMember
    }
    

    上下文接收器通过传播。

关于kotlin - 如果带注释的成员没有被特定 block 包围,则发出 IDE 警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74431315/

相关文章:

java - 通用类输入参数类型不匹配

datetime - 如何将包含日期和时区的字符串解析为DateTime

maven - Gradle本地依赖性测试

java - Maven 找不到 Struts2 依赖项

android - Lint 未检测到 "calling new methods on older versions"- 可以做什么?

Kotlin - 等待函数

kotlin - 传递和访问已传递到需要其父类(super class)型的类构造方法中的子类型的值和函数

kotlin - 如果您在 kotlin 中将 setter 设置为私有(private),如何分配新值?

java - IntelliJ 中的本地 Tomcat - 无法运行程序 catalina.bat

java - 在IntelliJ IDEA中导入Springframework源代码