[英]Referencing a class variable during call-by-name parameter
我有一個正在構建的庫,其中有一個特定的類,我想在其中使該類的一部分可定制。 用戶將能夠傳入一段代碼,以便他們可以根據需要修改內容(當然在某些范圍內)。 這實際上是為了避免讓用戶為小的差異擴展不同的類實現。
我原本以為我可以按名稱傳遞,但問題是在這種情況下我不能引用i2
(這對我來說很有意義)。
class MyClass[T](i: Int)(body: => T) {
var i2 = i
val something = body
}
val myc = new MyClass(1)(
//Do some work on i2 here
println(s"i2") //Compile error, i2 not found
)
有沒有辦法做這樣的事情,我可以在自定義body
定義期間引用內部類變量/方法? 我一直在尋找,我相信我在這里“不確定要問什么問題”領域。
繼承有什么問題?
class MyClass[T](s: T){
var i2 = s
}
val myc = new MyClass("You should not use mutable vars") {
i2 += "Because this is not how scala is intended to be used!"
i2 += "Providing library methods allowing users mutate internal structures"
i2 += " is especially bad!"
i2 += " You really, really, really, really should NOT be doing this!"
println(s"$i2")
}
或者,您可以將類實例作為參數傳遞給函數:
class MyClass[T](s: T)(body: MyClass[T] => Unit) {
var i2 = s
val something = body(this)
}
val myC = new MyClass("This approach") { x =>
x.i2 += " isn't really any better then the other one."
x.i2 += " If the user wants a different value for i2, "
x.i2 += " then why don't they pass it in to begin with?"
x.i2 += " what is the point in passing one value"
x.i2 += " and a function that replaces it with another?"
x.i2 += " Mutable vars are evil."
x.i2 += " Do not use them!"
println(x.i2)
}
您可以嘗試將 by-name 參數MyClass[T] => T
的函數,然后使用body(this)
調用它。 如果圍繞類中的初始化順序執行此操作,請小心。 我忘記了它是否能夠訪問MyClass
的非公共成員,盡管在使用它與定義的擴展點進行交互時這可能不是問題。
class MyClass[T](i: Int)(body: MyClass[T] => T) {
var i2 = i
val something = body(this)
}
類型推斷有點瘋狂,但是:
scala> val myc = new MyClass[Unit](1)(x => println(s"${x.i2}"))
1
val myc: MyClass[Unit] = MyClass@3f875466
scala> myc.something
當然,在something
例子中是Unit
value ()
,它被 sbt 控制台抑制。 通過讓body
成為一個高階函數,可以注入行為:
scala> val otherMyc = new MyClass[Int => Unit](1)(x => inc => x.i2 += inc)
val otherMyc: MyClass[Int => Unit] = MyClass@2ec032f4
scala> otherMyc.i2
val res4: Int = 1
scala> otherMyc.something(2)
scala> otherMyc.i2
val res6: Int = 3
我突然想到,您可能能夠使用只能具有在MyClass
中構造的實例的類(例如,在具有有限構造函數可見性的伴隨對象中定義的類)並將其作為第二個參數傳遞給body
(即讓body
a (MyClass[T], MyClass.PrivateEvidence) => T
)。 然后,您可以通過讓它們需要MyClass.PrivateEvidence
參數來使原本是私有的方法成為有效的私有方法(他們可以進一步檢查它是否是該實例的PrivateEvidence
)。 當然,本質上沒有什么可以阻止用戶提供的body
泄露PrivateEvidence
。
您還可以定義一個trait
,其中包含允許擴展操作的內容。 MyClass
然后構造該特征的實例並將其傳遞給body
,如下所示:
trait MyClassAccess {
def setI2(x: Int): Unit
def i2: Int
}
class MyClass[T](i: Int)(body: MyClassAccess => T) {
private var i2: Int = i
private val mcthis = this
private val access = new MyClassAccess {
def setI2(x: Int): Unit = mcthis.i2 = x
def i2: Int = mcthis.i2
}
val something = body(access)
}
scala> val adder: MyClassAccess => Int => Unit = { mca => increment => mca.setI2(mca.i2 + increment); println(s"i2 is ${mca.i2}") }
val adder: MyClassAccess => (Int => Unit) = $Lambda$5580/0x0000000840d16040@218339fd
scala> new MyClass(1)(adder)
val res9: MyClass[Int => Unit] = MyClass@c5adf11
scala> res9.something(1)
i2 is 2
scala> res9.something(2)
i2 is 4
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.