Scala中输入函数参数的类型约束
Posted
技术标签:
【中文标题】Scala中输入函数参数的类型约束【英文标题】:Type constraint on input function parameter in Scala 【发布时间】:2021-06-19 14:48:37 【问题描述】:我正在尝试创建一个高阶函数,它对输入函数接受的参数类型有一个上限。
展示问题的幼稚尝试的玩具示例:
class A
class B extends A
def AFunc(f: A => Unit): Unit =
AFunc((b: B) => )
//<console>:14: error: type mismatch;
// found : B => Unit
// required: A => Unit
// AFunc((b: B) => )
我认为这不起作用,因为函数的参数是逆变的,所以 B => Unit 是 A => Unit 的超类型。
有可能让它与像这样的多态函数一起工作:
class A
class B extends A
def AFunc[T <: A](f: T => Unit): Unit =
AFunc[B]((b: B) => )
这个解决方案的缺点是要求调用者知道传递函数参数的确切类型,尽管所有 AFunc 关心的类型是它是 A 的子类型。
有没有一种类型安全的方法可以在不显式传递类型的情况下强制执行类型约束?
【问题讨论】:
嗯,你不可能不知道参数的类型,因为你是 将它传入 :) 也许,你的意思是必须在调用时明确地拼出类型网站,但您实际上并不需要这样做,只需AFunc((b: B) => )
即可。
哦,哇,确实有效!我觉得有点傻。我想,学习一门新语言的痛苦越来越大。
@Dima 在没有明确指定类型的情况下似乎没有强制执行边界?例如,AFunc((b: Int) => ) 不会引发错误,但 AFunc[Int]((b: Int) => ) 会。
嗯 ...是的,看起来像一个错误:/但我玩了一下它,看看它实际上有多糟糕,一个发现,我真的不知道你是什么可以 do 使用此函数:在 AFunc
内部没有(良好/类型安全)调用 f
的方法(您无法获得正确类型的参数),所以...
这对我来说似乎很奇怪,但我猜这部分是因为它是一个坏主意,正如你所说的那样。我怀疑当我阅读更多类型级别的文档时,我会遇到一种标准的方式来做我想做的事。
【参考方案1】:
您的问题不是由于语言结构的限制,而是概念性的。函数的参数是逆变的是有原因的。
如果我们将您的代码稍微扩展为以下情况,您会期望发生什么:
class A
class B extends A
def AFunc(f: A => Unit): Unit =
f(new A) // let's use the function f
AFunc((b: B) => ) // ???
这将如何编译?方法 AFunc
显然需要一种方法来处理 A
类型的值,但您只提供了一种方法来处理这些值的一个子集(= B
类型的值)。
当然,您可以按照您的方式使您的方法具有多态性,顺便说一句,您甚至不需要在调用站点指定参数类型,因为它会被推断出来。但是,这不是“解决方案”。这只是另一回事。现在不是说“我需要一个处理A
类型的值的函数”,而是说“我需要一个处理A
的一个特定子类型的函数,但我会接受你决定的任何子类型” .
所以,正如 *** 上经常发生的那样,我不得不问你 - 你想要实现什么?你的方法AFunc
是要处理各种A
s,还是一次只处理一个特定的子类型?
如果是后者,使用上限进行参数化(如您所做的那样)应该没问题。如果您决定不在调用站点指定类型,请小心推断,因为有时您的代码可能会编译只是因为编译器推断出与您预期不同的内容(我从您问题中的 cmets 中看到您已经发现了这种行为)。但是,如果参数方法确实是您需要的,那么我不明白为什么在调用站点指定类型会成为问题。
尽管所有 AFunc 关心的类型是它是 A 的子类型。
当然,AFunc
不在乎。但是来电者确实如此。我的意思是,有人必须关心,对吧? :) 同样,如果不了解您正在解决的实际问题,很难继续讨论,但如果您想提供更多详细信息,我很乐意提供帮助。
【讨论】:
感谢您进一步阐明这一点。我现在明白为什么我的构造没有用了,尽管我仍然不清楚为什么对多态函数的类型推断会如此宽松。我在为嵌入式 DSL 做一些非常基本的原型设计时遇到了这个问题。正如我在原始帖子的 cmets 中提到的,我还有很多阅读工作要做,我相信这会给我一个更好的方向,并且可能比尝试解决这个特定的实现更有成效。以上是关于Scala中输入函数参数的类型约束的主要内容,如果未能解决你的问题,请参考以下文章