各个地方的Scala类型参数

时间:2016-12-23 14:04:22

标签: scala oop types functional-programming

我刚刚开始学习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通用的情况下? 因此,我不清楚何时以及在哪个位置(类或函数)应该放置类型参数。

2 个答案:

答案 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相同的参数。我希望namefirstName具有相同的类型,我可以通过这种方式强制执行。

方法saySomething有一个新的类型参数B。所以Person可以说任何类型的东西。

旁注

如您所述,您还可以将B替换为A并具有相同的行为:方法定义中的type参数将覆盖类定义中的类型参数。但为了便于阅读,应该避免这种情况。