我刚刚开始学习scala,并且对类型参数的一般理解存在一些问题。以前我学习过Haskell,但是在scala中我似乎很困惑。我不清楚我应该在哪里放置类型参数(近类定义或函数定义)。
考虑一下这个例子:
class Person[A] {
def sayName (name: A) = println(name)
}
将类型参数从类移动到函数是否有意义?
class Person {
def sayName[A] (name: A) = println(name)
}
或者我甚至可以在类和函数中保留类型参数,它会起作用。这有什么不同吗? 函数中的[A]参数是否会覆盖类定义中的相同参数?
我可以创建Person的实例或调用函数而不指向确切的类型。
val p = new Person();
那为什么这样呢?只是在我想要smth通用的情况下? 因此,我不清楚何时以及在哪个位置(类或函数)应该放置类型参数。
答案 0 :(得分:3)
如果在类级别声明类型参数,则在构造上指定实际类型,并且以后不能更改它 - 所有调用给定实例上的sayName
必须使用相同的类型
如果您在方法级别指定类型参数,则可以在方法的每个调用中指定其他类型
所以 - 如果类的实例应该总是应用于单个类型 - 使用类级别定义。
例如:
trait Animal
case class Dog() extends Animal
case class Cat() extends Animal
// A single owner has a *specific* pet,
// so it makes sense to declare type at class level
class Owner[A <: Animal] {
def feed(a: A) = ???
}
// A single RandomAnimalLover walking down the street,
// might feed both Dogs and Cats - so their feed method must be parameterized, and there's no use in adding a parameter at the class level
class RandomAnimalLover {
def feed[A <: Animal](a: A) = ???
}
val dog = Dog()
val cat = Cat()
val ownerA = new Owner[Dog]
val randomDude = new RandomAnimalLover
ownerA.feed(dog) // compiles
ownerA.feed(cat) // does not compile
randomDude.feed(dog) // compiles
randomDude.feed(cat) // compiles
最后,如果在类级别和方法级别声明类型参数两者 - 这是两个单独的参数。如果他们有不同的名字 - 两者都可以在任何地方使用;如果它们具有相同的名称,则方法级参数将 shadow 该方法的定义和实现范围内的类级别参数(但在类中没有其他地方)。
答案 1 :(得分:0)
您想要实现的目标将决定将类型参数放在何处。
将类型参数放在类定义中,以使类的某些属性具有通用性。它可以是val
,类参数或函数参数。
将type参数放在类定义中,以允许使用泛型类型调用方法。
class Person[A](name: A) {
def sayName = println(name)
def sayFirstName(firstName: A) = println(firstName)
def saySomething[B](thing: B) = println(s"$name says $thing")
}
// in console
scala> val p = new Person[String]("Barker")
p: Person[String] = Person@4f5a80a8
scala> p.sayName
Barker
scala> p.sayFirstName("John")
John
scala> p.sayFirstName(4)
<console>:14: error: type mismatch;
found : Int(4)
required: String
p.sayFirstName(4)
^
scala> p.saySomething("hello")
Barker says hello
scala> p.saySomething(42)
Barker says 42
方法sayFirstName
采用与name
相同的参数。我希望name
和firstName
具有相同的类型,我可以通过这种方式强制执行。
方法saySomething
有一个新的类型参数B
。所以Person
可以说任何类型的东西。
如您所述,您还可以将B
替换为A
并具有相同的行为:方法定义中的type参数将覆盖类定义中的类型参数。但为了便于阅读,应该避免这种情况。