当我编写像def foo[A,B]
这样的函数时,[A,B]
究竟是什么意思?我知道它是Polymorphic Method;但是什么时候使用foo [A]
与foo [A,B]
?
这是一个我不明白其中的例子。这个函数编译:
def map[B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
虽然这个没有编译。在A
引用所有A
之后,我不明白为什么f: A => B
不是必需的:
def map[A,B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
[error] ..../Stream.scala:61: type mismatch;
[error] found : h.type (with underlying type A)
[error] required: A
[error] foldRight(empty[B])((h,t) => cons(f(h), t))
(这来自FP in Scala练习之一)
附录
在阅读答案后,我添加了一些背景信息,以帮助未来的读者。该函数在特征中定义:
trait Stream[+A] {
...
def map[B](f: A => B):Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
...
}
因此错误是由类型阴影引起的,但请参阅@ acjay下面的优秀答案。
Google搜索scala type shadowing
并未导致任何scala文档中的直接定义,这很有趣,因为正如@travisbrown所说,它是最常见的一种我已经看到的初学者混乱的来源"。这里有一个讨论:Why does Scala support shadow variables?
答案 0 :(得分:4)
在第一个例子中,只有一个类型参数,因为它不是一个独立的函数,它是类Stream[A]
中的一个方法,它声明了第一个类型参数。大致如此:
class Stream[A] {
// ...
def map[B](f: A => B): Stream[B] =
foldRight(empty[B])((h,t) => cons(f(h), t))
// ...
}
所以你从周围的类范围中得到A
。相反,假设您在伴随对象上创建了map
方法。在这种情况下,伴随对象没有类型参数,因此您必须在方法上定义两个参数:
class Stream[A] {
// ... methods, with foldRight, but no `map`
}
object Stream {
// ...
def map[A, B](stream: Stream[A])(f: A => B): Stream[B] =
stream.foldRight(empty[B])((h,t) => cons(f(h), t))
// ...
}
第二个选项的使用方式略有不同。您会说Stream.map(myStream)(myMappingFunction)
而不是myStream.map(myMappingFunction)
。这两个选项都是完全有效的,但将该方法放在课堂中可能更为惯用。
因此,要回答您的问题,当两个或多个参数和/或返回类型需要是通用的时,您在方法上使用多个类型参数。您也可以对类使用两个类型参数,例如(忽略方差):
键入Map[A, B]
- A
是键类型,B
是值类型
输入Tuple2[A, B]
(更好地称为(A, B)
) - A
是第一个元素的类型,B
是第二个元素的类型
键入Function1[A, B]
(更好地称为A => B
) - A
是参数类型,B
是返回类型
......等等。