[英]Foiled by path-dependent types
I'm having trouble using, in one trait, a Parser returned from a method in another trait. 我在一个特性中使用了一个Parser从另一个特征中的方法返回时遇到了麻烦。 The compiler complains of a type mismatch and it appears to me that the problem is due to the path-dependent class. 编译器抱怨类型不匹配,在我看来问题是由路径依赖类引起的。 I'm not sure how to get what I want. 我不知道如何得到我想要的东西。
trait Outerparser extends RegexParsers {
def inner: Innerparser
def quoted[T](something: Parser[T]) = "\"" ~> something <~ "\""
def quotedNumber = quoted(inner.number) // Compile error
def quotedLocalNumber = quoted(number) // Compiles just fine
def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}
}
trait Innerparser extends RegexParsers {
def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}
}
And the error: 而错误:
[error] /Path/to/MyParser.scala:6: type mismatch
[error] found : minerals.Innerparser#Parser[Int]
[error] required: Outerparser.this.Parser[?]
[error] def quotedNumber = quoted(inner.number)
I sort-of get the idea: each "something" method is defining a Parser type whose path is specific to the enclosing class (Outerparser or Innerparser). 我得到了一个想法:每个“东西”方法定义一个Parser类型,其路径特定于封闭类(Outerparser或Innerparser)。 The "quoted" method of Outerparser expects an an instance of type Outerparser.this.Parser but is getting Innerparser#Parser. Outerparser的“引用”方法需要一个类型为Outerparser.this.Parser的实例,但正在获取Innerparser#Parser。
I like to be able to use quoted with a parser obtained from this class or some other class. 我希望能够使用从此类或其他类获得的解析器引用。 How can I do that? 我怎样才能做到这一点?
For better or for worse, the way you usually use the Scala parser combinator libraries is to wrap everything in an enclosing trait or object that extends
a trait like RegexParsers
. 为了更好或更坏,您通常使用Scala的解析器组合库的方法是在一个封闭的特征或对象来包装的一切extends
像一个特点RegexParsers
。 I'm not quite sure why the API was designed like this. 我不太清楚为什么API是这样设计的。
But, anyway, once they all belong to the same instance of RegexParsers
, they all see the same Parser
type: 但是,无论如何,一旦它们都属于同一个RegexParsers
实例,它们都会看到相同的Parser
类型:
trait Everything extends RegexParsers {
trait Outerparser {
...
}
trait Innerparser {
...
}
}
And everyone is happy. 每个人都很开心。
Don't think of it as putting everything in the same scope; 不要认为它把所有东西放在同一范围内; think of it as the parser-combinator API's kooky way of importing names, ie, you could just as easily do 把它想象成解析器 - 组合器API导入名称的怪异方式,也就是说,你可以轻松地做到
import scala.util.parsing.combinator._
import scala.util.parsing.input._
object blah extends RegexParsers
import blah._
trait Outerparser {
...
}
trait Innerparser {
...
}
You can use a self-type annotation to make it compile while still preserving the modularity: 您可以使用自我类型注释使其进行编译,同时仍保留模块性:
trait OuterParser extends RegexParsers { this: InnerParser =>
def quoted[T](something: Parser[T]) = "\"" ~> something <~ "\""
def quotedNumber = quoted(number) // Compile error
}
trait InnerParser extends RegexParsers {
def number: Parser[Int] = ("""[1-9][0-9]*"""r) ^^ {str => str.toInt}
}
object MyCompleteParser extends OuterParser with InnerParser
The self-type annotation basically says that OuterParser depends InnerParser (they must be mixed together to create a proper instantiatable class). 自我类型注释基本上说OuterParser依赖于InnerParser(它们必须混合在一起才能创建一个适当的可实例化类)。 The compiler thus knows for sure that in OuterParser and InnerParser, Parser
refers to the same type. 因此,编译器确切地知道在OuterParser和InnerParser中, Parser
引用相同的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.