【问题标题】:How to force a compile time function's argument to be of a specific type in Scala?如何强制编译时函数的参数是 Scala 中的特定类型?
【发布时间】:2017-05-05 01:35:13
【问题描述】:

当我们只知道对象类型是Any 时,有没有办法强制将函数参数的编译类型设置为函数签名中定义的预期类型?让我用一个简单的例子来演示一下。

鉴于我们已经定义了以下三个函数:

def writeInt(value: Int): Unit { ... }

def writeString(value: String): Unit { ... }

def get(name: String): Any = { ... }

如何在不强制程序员在其程序中引用 writeInt 函数明确声明应该使用 get 返回的内容 .asInstanceOf[Int] 的情况下成功编译以下代码:

writeInt(get("dividend").asInstanceOf[Int]) // this works...
writeInt(get("dividend"))                   // but this does not :(

由于get 可能返回Any 对象,它可能是IntString,有没有一种优雅的方法可以在Scala 中解决它而没有丑陋的@ 987654331@符号?

请注意,在程序的其他部分,我希望能够使用相同的函数分别编写这段代码,而无需再次输入.asInstanceOf[String]

writeString(get("name").asInstanceOf[String]) // this works...
writeString(get("name"))                      // but this does not :(

基本上,我知道get("dividend") 返回一个Intget("name") 返回一个String。但是我怎样才能让编译器知道它没有太多的混乱呢?

【问题讨论】:

  • 我认为简短的回答是“不”。如果你的返回类型是 Any 那么编译器就无法知道。
  • 一个想法是让你的 getter 使用类型而不是字符串 def get[Name]: String ... def get[Id]: Long。这里的 Name 和 Id 是您创建的自定义类型。
  • 感谢您提出一个有趣的想法,但它不适用于我的用例。字符串不能用类型替换,因为它将是来自外部世界的任意字符串。它实际上可以是任何东西。
  • 那么在这种情况下,在编译时很难知道类型。 get("a") 可以是 String,而 get("b") 可以是 Long。我还假设任意数据也可以在运行时存储?
  • 嗯,问题是在编译时知道类型并不难,因为我在编译时已经知道它们(长话短说:我将这些信息存储在 HashMap 中保存每个键的类名和实际值),所以这里没有歧义。这意味着我知道 get("a") 是一个字符串,而 get("b") 是一个 Long,并且我在编译时已经掌握了这些信息。问题是,如何在定义“def get(name:String)”方法的代码中以通用方式访问它,而无需对其结果显式调用“asInstanceOf”。

标签: java scala functional-programming


【解决方案1】:

您可以为您的 write 方法使用包装器。

def writeAny(a: Any): Unit = a match {
  case s: String => writeString(s)
  case i: Int    => writeInt(i)
}

更好的解决方案是让您的get() 方法返回Either[String,Int]。然后你的代码可以做这样的事情:

get(str).fold(writeString, writeInt)

作为一般规则,应尽可能避免使用Any

【讨论】:

  • 这些“写”方法在这里仅作为示例给出。它们不是您所说的“我的”,因此我无法真正修改它们。您可以用推理中可以想到的任何内置或自定义方法替换它们,例如"def substring(int beginIndex)" 或 "def startsWith(String prefix)" 如果有帮助的话。我控制的唯一部分是“def get(name:String)”方法的定义。我想知道是否存在一种将它参数化的方法,它允许我不强制转换它的返回类型,但以某种方式从它的“名称”参数推断它,例如我知道“股息”总是“整数”。
  • 我只在非正式意义上使用了“您的”一词,即 you 选择以它们为例来引起我们的注意,而 your 问题是关于如何与他们合作。作为一般规则,编译器看到的是类型,而不是值。因此,除了为此目的编写宏之外,编译器无法根据在某些情况下可能是用户输入结果的内容做出类型决定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-30
相关资源
最近更新 更多