我有两个特点:
trait Repository[T] {
def insert(obj: T): Task[T]
}
trait RoleRepository extends Repository[Role]
然后我添加了RoleRepository的实现:
class RoleRepositoryImplem(val db: Db) extends RoleRepository {
def insert(role: Role): Task[Role] = {
//some implementation here
}
在我的实施中,我犯了一个错误(正如我所想):我已将参数命名为" role"而不是" obj"。但项目实际编译并运行得很好。它看起来很奇怪我认为如果有人根据特质存储库编写自己的代码,这会导致很多混乱。我在我的项目中使用Scala 2.12.2。有人可以解决这个问题吗?为什么会发生这种情况以及如何解决这个问题?
答案 0 :(得分:2)
您使用的名称取决于编译时调用时已知的类型,而不是实现的真实名称。
例如:
val repo: RoleRepositoryImplem = new RoleRepositoryImplem(db)
repo.insert(role = foobar) // this works
val repoAsTrait: Repository[Role] = repo
repoAsTrait.insert(obj = foobar) // role name no longer works
我发现它确实令人困惑:当您只知道自己有Repository
时,则使用更通用的名称obj
,否则role
如果您知道通话时的准确类型。
请记住,当scala编译为字节码时,参数名称将丢失,因为字节码不处理命名参数。因此,在运行时无法知道参数的真实名称是什么(不包括slooooow内省)。 scala编译器只是将名称转换为参数中的位置。
答案 1 :(得分:2)
方法的参数只是它接受的type
的名称。
假设您有一个方法addNumber(number: T)
,当您override
方法时,您必须遵循相同的签名,但您可以为参数提供一个更好的名称,这在该上下文中更有意义,例如addNumber(integer: Integer)
。
以Bag
为例,其中包含item
s(项目是此处的通用术语)
trait Bag[T] {
def addToBag(item: T)
def items(): List[T]
}
如果包中包含水果,你会向其中添加fruit
,因此将输入参数调用为fruit: Fruit
会更有意义,但是你可以根据需要调用它。
case class Fruit(name: String)
trait FruitBag extends Bag[Fruit]
class MyFruitBag extends FruitBag {
var list = scala.collection.mutable.ListBuffer[Fruit]()
override def addToBag(fruit: Fruit): Unit = {
println("adding item")
list.+=:(fruit)
}
override def items(): List[Fruit] = list.toList
}
如果包中包含Toy
s,您将需要将输入参数调用为toy
,这更具上下文性,但您可以再次为其提供所需的名称。
case class Toy(name: String)
trait ToyBag extends Bag[Toy]
class MyToysBag extends ToyBag {
var list = scala.collection.mutable.ListBuffer[Toy]()
override def addToBag(toy: Toy): Unit = {
println("adding item")
list.+=:(toy)
}
override def items(): List[Toy] = list.toList
}
摘要是当您覆盖仅override
签名的方法时,不一定是参数的确切名称,参数是根据子类的上下文命名的。
答案 2 :(得分:1)
重写/实现的方法参数的名称在超类/特征和子类中不需要相同。在Scala和更多语言中都是如此。在上述情况下,OO语言通常不需要相同的参数名称。