我有一個資料結構,其中的成員不是執行緒安全的,呼叫者需要鎖定資源以進行適當的讀寫。這是一個最小的代碼示例:
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。有沒有辦法在不為 IDE 撰寫自定義插件的情況下在 IntelliJ 中執行此操作?
uj5u.com熱心網友回復:
我認為這是一種 hack,但使用背景關系接收器可能會起作用。我不認為它們打算以這種方式使用。
您可以宣告一個虛擬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 }背景關系接收器被傳播。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/533901.html
標籤:科特林智能理念
