Scala 3中方法无法匹配等效函数签名问题求助
Scala 3.2.1重载柯里化方法适配问题解析
问题代码
class Test[F[_]] { def error(message: => String): F[Unit] = {??? } def error(t: Throwable)(message: => String): F[Unit] = {??? } def test1(f: String => F[Unit]): Unit = {} def test2(f: Throwable => String => F[Unit]): Unit = {} test1(error) // 编译正常 test2(error) // 编译报错 }
报错信息
None of the overloaded alternatives of method error in class Test with types
(t: Throwable)(message: => String): F[Unit]
(message: => String): F[Unit]
match expected type Throwable => String => F[Unit]
test2(error)
根本原因
这不是类型擦除问题,不需要添加ClassTag,核心原因是传名参数的函数适配规则:
test1能通过:第一个error重载的传名参数message: => String,编译器会自动适配为String => F[Unit]类型(把传名参数隐式转换为接受String的函数),符合test1的参数要求。test2失败:第二个error是柯里化方法,第二个参数是传名参数message: => String,它的eta展开类型是Throwable => (() => String) => F[Unit],而test2需要的是Throwable => String => F[Unit],两者返回的函数类型不匹配(一个接受() => String,一个接受String)。- 替换
F[Unit]为Unit能编译:因为Scala对返回值为Unit的方法有特殊宽松适配,允许忽略传名参数和普通参数的差异,但泛型返回类型F[Unit]不享受这个规则。
解决方案
方案1:修改test2的参数类型以匹配传名参数的展开类型
class Test[F[_]] { def error(message: => String): F[Unit] = {??? } def error(t: Throwable)(message: => String): F[Unit] = {??? } def test1(f: String => F[Unit]): Unit = {} // 把参数类型改为接受() => String的函数 def test2(f: Throwable => (() => String) => F[Unit]): Unit = {} test1(error) test2(error) // 现在编译正常 }
方案2:修改error的重载方法,将传名参数改为普通参数
class Test[F[_]] { def error(message: => String): F[Unit] = {??? } // 把第二个参数从传名改为普通String参数 def error(t: Throwable)(message: String): F[Unit] = {??? } def test1(f: String => F[Unit]): Unit = {} def test2(f: Throwable => String => F[Unit]): Unit = {} test1(error) test2(error) // 现在编译正常 }
方案3:手动转换error为test2需要的类型
如果不想修改原有方法签名,可以手动做类型适配:
class Test[F[_]] { def error(message: => String): F[Unit] = {??? } def error(t: Throwable)(message: => String): F[Unit] = {??? } def test1(f: String => F[Unit]): Unit = {} def test2(f: Throwable => String => F[Unit]): Unit = {} test1(error) // 手动将传名参数适配为普通String参数 test2(t => (msg: String) => error(t)(msg)) }
内容的提问来源于stack exchange,提问作者modo_lv
相关产品推荐
相关产品推荐

