Scala 应用不带参数
Scala apply with no parameters
我想创建一个程序,在收到请求时生成随机的东西,例如下面示例中的字母。我已经定义了一个抽象 class 和一个伴随对象到 return 子 class 之一。
abstract class Letter
class LetterA extends Letter {
override def toString = "A"
}
class LetterB extends Letter {
override def toString = "B"
}
class LetterC extends Letter {
override def toString = "C"
}
object Letter {
def apply = RNG.d(3) match {
case 1 => new LetterA
case 2 => new LetterB
case 3 => new LetterC
}
override def toString = "Random Letter"
}
我的梦想是我将能够使用 Letter
来获得类型为 A、B 或 C 的随机字母。但是使用这段代码,它只给了我字母对象。 Letter.apply
给我 A、B 或 C,但很丑。
如果我将 apply
函数更改为 apply()
那么事情会好一些,因为我可以使用 Letter()
来获取我的随机字母之一,但是 Letter
仍然给我对象。
有什么我可以做的,以便将某些东西分配给 Letter
实际上解析为 LetterA
、LetterB
或 LetterC
之一?
你的问题的答案是否定的,你无法区分 Letter.type 和 Letter.apply,所以你需要一个解决方法。
我建议你使用 Type-Class 模式,它比向伴随对象添加随机生成的应用方法更具扩展性
trait RandomGenerator[T] {
def gen: T
}
implicit object RandomLetter extends RandomGenerator[Letter] {
private val rnd = new Random()
def gen = (rnd.nextInt(3) + 1) match {
case 1 => new LetterA
case 2 => new LetterB
case 3 => new LetterC
}
}
def random[T: RandomGenerator]: T =
implicitly[RandomGenerator[T]].gen
println(random[Letter])
println(random[Letter])
println(random[Letter])
您可以在伴随对象中提供从 Letter.type
到 Letter
的隐式转换:
implicit def asLetter(companion: Letter.type): Letter = companion.apply
然后你可以使用Letter
得到一个可以隐式转换为Letter
class的对象。例如:
val x: Letter = Letter
val letters: Seq[Letter] = Seq.fill(10)(Letter)
但请记住,这样您将始终必须将对象归因于正在使用的 class。
注意:我不认为这是一个特别好的主意,但我只是想证明这是可能的!
您可以将 Letter
变成 def
(如有必要,在包对象上)。为简单起见,我将东西包装在外部对象中:
object Letters {
// Your class definitions
def Letter = RNG.d(3) match {
case 1 => new LetterA
case 2 => new LetterB
case 3 => new LetterC
}
}
使用大写名称的 def
不是很惯用,但出于某些 DSL 的考虑,IMO 可以接受。
我想创建一个程序,在收到请求时生成随机的东西,例如下面示例中的字母。我已经定义了一个抽象 class 和一个伴随对象到 return 子 class 之一。
abstract class Letter
class LetterA extends Letter {
override def toString = "A"
}
class LetterB extends Letter {
override def toString = "B"
}
class LetterC extends Letter {
override def toString = "C"
}
object Letter {
def apply = RNG.d(3) match {
case 1 => new LetterA
case 2 => new LetterB
case 3 => new LetterC
}
override def toString = "Random Letter"
}
我的梦想是我将能够使用 Letter
来获得类型为 A、B 或 C 的随机字母。但是使用这段代码,它只给了我字母对象。 Letter.apply
给我 A、B 或 C,但很丑。
如果我将 apply
函数更改为 apply()
那么事情会好一些,因为我可以使用 Letter()
来获取我的随机字母之一,但是 Letter
仍然给我对象。
有什么我可以做的,以便将某些东西分配给 Letter
实际上解析为 LetterA
、LetterB
或 LetterC
之一?
你的问题的答案是否定的,你无法区分 Letter.type 和 Letter.apply,所以你需要一个解决方法。
我建议你使用 Type-Class 模式,它比向伴随对象添加随机生成的应用方法更具扩展性
trait RandomGenerator[T] {
def gen: T
}
implicit object RandomLetter extends RandomGenerator[Letter] {
private val rnd = new Random()
def gen = (rnd.nextInt(3) + 1) match {
case 1 => new LetterA
case 2 => new LetterB
case 3 => new LetterC
}
}
def random[T: RandomGenerator]: T =
implicitly[RandomGenerator[T]].gen
println(random[Letter])
println(random[Letter])
println(random[Letter])
您可以在伴随对象中提供从 Letter.type
到 Letter
的隐式转换:
implicit def asLetter(companion: Letter.type): Letter = companion.apply
然后你可以使用Letter
得到一个可以隐式转换为Letter
class的对象。例如:
val x: Letter = Letter
val letters: Seq[Letter] = Seq.fill(10)(Letter)
但请记住,这样您将始终必须将对象归因于正在使用的 class。
注意:我不认为这是一个特别好的主意,但我只是想证明这是可能的!
您可以将 Letter
变成 def
(如有必要,在包对象上)。为简单起见,我将东西包装在外部对象中:
object Letters {
// Your class definitions
def Letter = RNG.d(3) match {
case 1 => new LetterA
case 2 => new LetterB
case 3 => new LetterC
}
}
使用大写名称的 def
不是很惯用,但出于某些 DSL 的考虑,IMO 可以接受。