斯卡拉案例类禁止按名称参数? [英] Scala case class prohibits call-by-name parameters?

查看:154
本文介绍了斯卡拉案例类禁止按名称参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个无限列表:

 抽象类MyList [+ T] 
case对象MyNil extends MyList [Nothing]
case class MyNode [T](h:T,t:=> MyList [T])扩展MyList [T]

//错误:`val'参数可能不是名称

问题在于呼叫方



我听说这是因为 val var 构造函数参数不允许用于名称调用。例如:

  class A(val x:=> Int)
//错误:`val'参数可能不是名称

但是矛盾的是,正常的构造函数参数仍然是 val ,尽管 private 。例如:

  class A(x:=> Int)
//传递
code>






所以问题:


  • 问题真的存在于 val 还是 var


    • 如果是这样。由于按名称调用是为了延迟计算,为什么不能执行 val var 计算(或初始化)被延期?


  • 如何绕过cass类来实现无限列表?

  • 不存在任何矛盾: class A(x:=> Int)

    解决方案 >相当于 class A(private [this] val x:=> Int)而不是 class A(private val x:=> INT) private [this] 标记一个值instance-private,而没有进一步规范的private-modifier允许从该类的任何实例访问值。



    不幸的是,定义一个的case类A(private [this] val x:=> Int)不是允许。我认为这是因为case-classes需要访问其他实例的构造函数值,因为它们实现了 equals 方法。



    然而,您可以实现案例类可以手动提供的功能:

      abstract class MyList [+ T] 

    class MyNode [T](val h:T,t:=> MyList [T])扩展MyList [T] {

    def getT = t //我们需要能够访问t

    / *编辑:实际上,这也会导致无限递归
    重写def equals(other:任何):Boolean = other match {
    case MyNode(i,y)if(getT == y)&& (h == i)=> true
    case _ => false
    } * /

    覆盖def hashCode = h.hashCode

    覆盖def toString =MyNode [+ h +]

    }

    object MyNode {
    def apply [T](h:T,t:=> MyList [T])= new MyNode(h,t)
    def unapply [T](n:MyNode [T])= Some(nh - > n.getT)
    }

    要检查这段代码,你可以试试:

      def main(args:Array [String ]):Unit = {
    lazy val first:MyNode [String] = MyNode(hello,second)
    lazy val second:MyNode [String] = MyNode(world,first)
    println(first)
    println(second)
    first match {
    case MyNode(hello,s)=> println(第二个节点是+ s)
    案例_ => println(false)
    }
    }

    不幸的是,我没有肯定知道为什么禁止使用名为val和var的成员。但是,至少有一个危险:考虑case-classes如何实现 toString ;调用每个构造函数值的 toString - 方法。这可以(并且在这个例子中)导致价值无限地自我调节。您可以通过将 t.toString 添加到 MyNode toString - 方法。



    编辑:在阅读Chris Martin的评论之后: equals 的实现也将构成这个问题可能比执行 toString (它主要用于调试)和 hashCode (其中只会导致更高的冲突率,如果你不能把这个参数考虑在内)。你必须仔细考虑如何实现等于是有意义的。

    I want to implement an infinite list:

    abstract class MyList[+T]
    case object MyNil extends MyList[Nothing]
    case class MyNode[T](h:T,t: => MyList[T]) extends MyList[T]
    
    //error: `val' parameters may not be call-by-name
    

    the problem is the call-by-name is not allowed.

    I've heard that it is because val or var constructor parameter is not allowed for call-by-name. For example:

    class A(val x: =>Int) 
    //error: `val' parameters may not be call-by-name
    

    But the contradiction is that the normal constructor parameter is still val, despite private. For example:

    class A(x: =>Int) 
    // pass
    


    So the question :

    • Is the problem really about val or var ?
      • If that. Since the point for call-by-name is to defer computation, Why could not val or var computation(or initialization) be deferred?
    • How to get around the cass class to implement an infinite list?

    解决方案

    There is no contradiction: class A(x: => Int) is equivalent to class A(private[this] val x: => Int) and not class A(private val x: => Int). private[this] marks a value instance-private, while a private-modifier without further specification allows accessing the value from any instance of that class.

    Unfortunately, defining a case class A(private[this] val x: => Int) is not allowed either. I assume it is because case-classes need access to the constructor values of other instances, because they implement the equals method.

    Nevertheless, you could implement the features that a case class would provide manually:

    abstract class MyList[+T]
    
    class MyNode[T](val h: T, t: => MyList[T]) extends MyList[T]{
    
      def getT = t // we need to be able to access t 
    
      /* EDIT: Actually, this will also lead to an infinite recursion
      override def equals(other: Any): Boolean = other match{
        case MyNode(i, y) if (getT == y) && (h == i) => true
        case _ => false
      }*/
    
      override def hashCode = h.hashCode
    
      override def toString = "MyNode[" + h + "]"
    
    }
    
    object MyNode {
      def apply[T](h: T, t: => MyList[T]) = new MyNode(h, t)
      def unapply[T](n: MyNode[T]) = Some(n.h -> n.getT)
    }
    

    To check this code, you could try:

    def main(args: Array[String]): Unit = {
      lazy val first: MyNode[String] = MyNode("hello", second)
      lazy val second: MyNode[String] = MyNode("world", first)
      println(first)
      println(second)
      first match {
        case MyNode("hello", s) => println("the second node is " + s)
        case _ => println("false")
      }
    }
    

    Unfortunately, I do not know for sure why call-by-name val and var members are prohibited. However, there is at least one danger to it: Think about how case-classes implement toString; The toString-method of every constructor value is called. This could (and in this example would) lead to the values calling themselves infinitely. You can check this by adding t.toString to MyNode's toString-method.

    Edit: After reading Chris Martin's comment: The implementation of equals will also pose a problem that is probably more severe than the implementation of toString (which is mostly used for debugging) and hashCode (which will only lead to higher collision rates if you can't take the parameter into account). You have to think carefully about how you would implement equals to be meaningfull.

    这篇关于斯卡拉案例类禁止按名称参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆