【问题标题】:equivalent of pythons repr() in scala相当于scala中的pythons repr()
【发布时间】:2011-12-12 16:03:49
【问题描述】:

scala 中是否有相当于 Pythons repr 的函数?

即一个你可以给任何 scala 对象的函数,它会产生一个对象的字符串表示,它是有效的 scala 代码。

例如:

val l = List(Map(1 -> "a"))

print(repr(l))

会产生

List(Map(1 -> "a"))

【问题讨论】:

  • 我认为这在像 python 这样更动态的语言中更有意义,因为你可以稍后 eval 那个字符串并用它做一些事情
  • 我不认为这样的特性真的有意义,因为 Scala 是一种静态类型的语言。我想您可以将 #toSource() 方法混合到您创建的任何类中,但在我看来,您这样做的唯一原因是为了教育(或者可能是出于调试目的)。
  • 是的..我不会调试它。这也是我在 python 中使用它的原因。
  • 我个人使用这样的功能来编译手工游戏,作为中间表示。所以即使没有 eval,也可以用来创建 scala 代码以供进一步重用。

标签: scala


【解决方案1】:

每个对象大多只有toString 方法。 (继承自 Java。)这可能会或可能不会导致可解析的表示。在大多数一般情况下,它可能不会;没有真正的约定,因为在 Python 中有,但一些集合类至少尝试这样做。 (只要它们不是无限的。)

当涉及到字符串时,它当然已经达到了崩溃的地步

"some string".toString == "some string"

但是,为了获得适当的表示,我们需要

repr("some string") == "\"some string\""

据我所知,Scala 中没有这样的东西。不过,一些序列化库可能对此有所帮助。

【讨论】:

  • toString 方法往往不会产生可编译的输出。例如 List(1 -> "a") 给你 List[(Int, java.lang.String)] = List((1,a))
  • 是的。真的。是琴弦。不过,只使用整数就可以了。
【解决方案2】:

根据Java equivalent of Python repr()?的逻辑,我写了这个小函数:

object Util {
  def repr(s: String): String = {
    if (s == null) "null"
    else s.toList.map {
      case '\0' => "\\0"
      case '\t' => "\\t"
      case '\n' => "\\n"
      case '\r' => "\\r"
      case '\"' => "\\\""
      case '\\' => "\\\\"
      case ch if (' ' <= ch && ch <= '\u007e') => ch.toString
      case ch => {
        val hex = Integer.toHexString(ch.toInt)
        "\\u%s%s".format("0" * (4 - hex.length), hex)
      }
    }.mkString("\"", "", "\"")
  }
}

我已经尝试了一些值,它似乎工作,虽然我很确定坚持 U+FFFF 上方的 Unicode 字符会导致问题。

【讨论】:

    【解决方案3】:

    如果您处理案例类,您可以混合使用以下 trait StringMaker,以便在此类案例类上调用 toString 将起作用,即使它们的参数是字符串:

    trait StringMaker {
      override def toString = {
        this.getClass.getName + "(" +
        this.getClass.getDeclaredFields.map{
          field =>
            field.setAccessible(true)
            val name = field.getName
            val value = field.get(this)
            value match {
              case s: String => "\"" + value + "\"" //Or Util.repr(value) see the other answer
              case _ => value.toString
            }
        }
        .reduceLeft{_+", "+_} +
        ")"
      }
    }
    trait Expression
    case class EString(value: String, i: Int) extends Expression with StringMaker
    case class EStringBad(value: String, i: Int) extends Expression //w/o StringMaker
    val c_good = EString("641", 151)
    val c_bad = EStringBad("641", 151)
    

    将导致:

    c_good: EString = EString("641", 151)
    c_bad: EStringBad = EStringBad(641,151)
    

    所以你可以解析回第一个表达式,但不能解析第一个。

    【讨论】:

    • 有趣的建议。现在我们有了宏,我们可以用宏做点什么吗……应该不用反射就可以做到吗?
    • 这很好。我可能已经把 .repr() 作为一个单独的函数,所以你仍然可以得到 .toString() 但如果你想要它也可以得到 .repr() 。
    • 其实我之前没有注意到这个,但是如果String值包含引号或者其他奇怪的字符,我认为你的代码不会起作用。在这种情况下,您必须使用我在上面写的 Util.repr(value) 之类的东西。
    【解决方案4】:

    不,Scala 中没有这样的功能。

    【讨论】:

    • 这也不是 Python 的真正特性。只是一个约定。
    • 这是一个非常受人尊敬的约定,它成为一个非常有用的功能!
    猜你喜欢
    • 1970-01-01
    • 2014-03-06
    • 2020-02-16
    • 1970-01-01
    • 2010-11-19
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多