【问题标题】:Scala not resolving X as Y, even though X extends YScala 没有将 X 解析为 Y,即使 X 扩展了 Y
【发布时间】:2014-01-30 05:24:59
【问题描述】:

[见下面的sn-p] 我读到我有一个 X,它是一个棋子,我有一个需要棋子的玩家。玩家 Me 试图用 Piece X 来定义这个 Piece。然而 Scala 并没有将 X 识别为一个片段,而是看到了“X.type”。 X.type 是什么意思?我不确定我的问题是什么,所以我很难搜索。

我不明白这怎么会是类型阴影 [参见Scala really weird Type Mismatch],因为我没有指定另一个“Piece”,而是只指定我需要一个“Piece”。

似乎有些东西阻止了 Scala 将 X 解析为 Piece。

在 REPL 中尝试

trait Piece { val piece: Char }
case class X extends Piece { val piece: Char = 'X' }

trait Player { val piece: Piece }
case class Me extends Player { val piece: Piece = X }

结果

error: type mismatch;
 found   : X.type
 required: Piece
       case class Max extends Player { val piece: Piece = X }

【问题讨论】:

    标签: scala types type-mismatch traits mismatch


    【解决方案1】:

    这可能是因为 X 只描述了一个类(所以它实际上是一个 type),而 Scala 期望一个 object(或实例)类型片。在第一种情况下这样做你会得到同样的错误:

    case class X extends Piece { val piece: Char = Char }
    

    如您所见,您的版本有效,因为您传递的是特定字符,而不是类型。如果你想让你的代码工作,你可能必须创建一个新对象并将其传入:

    case class Me extends Player { val piece: Piece = new X }
    

    编辑:正如下面评论中提到的 OP,使用 X() 也可以,因为 X 是一个案例类,它有一个隐式的 apply() 方法:

    case class Me extends Player { val piece: Piece = X() }
    

    【讨论】:

    • 啊,非常感谢!我通常有一个参数,所以我从来没有遇到过这个问题。即使使用 X() 也可以解决问题。没有意识到一个类是一种类型。哇,现在模式匹配更有意义了,类是实例的蓝图这一事实更加清晰,令人敬畏。它刚刚点击!
    • 这个答案实际上并不完全正确。你能更新它以符合我的答案吗?只是为了,你知道,乐于助人。
    【解决方案2】:

    您将X 类型分配给变量piece,而不是X 的实例。

    【讨论】:

      【解决方案3】:

      当您编写case class X 时,您还创建了一个同伴object X,它有一个成员apply,可以让您说X()。在对 Scala 有一些经验之后,这一切都是显而易见的。

      X.type 是对象 X 的单例类型。正如其他答案所说,它与“分配类型”无关。

      当您说X 作为值时,它表示该对象。它是一个术语(即值),而不是一个类型。

      为了创建一个新的 X,每个人都写 X(),这正是 X.apply(),而不是 new X()。绝不?是的,几乎从来没有。

      请注意,无参数案例类早已被弃用。

      【讨论】:

      • 谢谢!是的,我认为您不能“分配类型”,除非您执行type Cool = List[Int] 之类的操作,在其中创建一个新类型“Cool”,它是一个 List[Int] 对吗?
      • 从技术上讲,在这种情况下您不会创建新类型 - Cool 是类型别名 - 意味着它与 List[Int] 完全相同。创建一个新类型意味着class Cool extends List[Int]
      【解决方案4】:

      不推荐使用没有参数的案例类。请改用case class X()case class Me()。这样,您将不得不使用 X() 调用创建 X 类的对象,如其他答案中所述。

      您也可以使用case objects:

      case object X extends Piece { val piece: Char = 'X' }.
      

      事实上,如果你在这里使用case对象,你的代码就会开始工作:

      case class Me extends Player { val piece: Piece = X }  // Works fine
      

      不过,这取决于您的要求。您可能需要多个X 实例;那么 case 对象不适合你。

      【讨论】:

      • 谢谢!清除 REPL 抱怨弃用的原因。当您只需要该对象的一个​​实例时,您是否使用案例对象而不是案例类?我注意到,如果您使用 case 对象,则无法像 case(x: X) => println("I am X") 那样进行模式匹配,因为“X”不再是一种类型,而是对“X”对象的引用。我猜在这种情况下你会检查类似if (x == X) println("X thanks you")
      • 可以匹配,使用case X => println("I am X")
      • @Miles,不,if 不需要。可以直接匹配,比如case X => ...。我写这篇文章是因为你可能没有收到关于 sourcedelica 评论的通知。
      猜你喜欢
      • 1970-01-01
      • 2022-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      • 1970-01-01
      相关资源
      最近更新 更多