【问题标题】:Scala: no-name parameters in function with List and OptionScala:带有List和Option的函数中的无名参数
【发布时间】:2019-05-22 16:34:05
【问题描述】:

2 个不同的示例,第一个有效:

  import cats.syntax.either._
  val e = 10.asRight[String]
  def i2s(i:Int):String = i.toString
  e.map(i => List(i2s(i))) //using explicit parameter
  e.map(List(i2s(_)))   //using no-name _ parameter

现在与 Option 相同的示例未编译:

e.map(Option(i2s(_))) 

错误:

Error:(27, 15) type mismatch;
 found   : Option[Int => String]
 required: Int => ?
  e.map(Option(i2s(_)))

使用显式参数它可以正常工作:

e.map(i => Option(i2s(i)))

在这两种情况下,apply 方法都是通过 List 和 Option 调用的。 List.apply签名:

 def apply[A](xs: A*): List[A] = ???

Option.apply签名:

 def apply[A](x: A): Option[A]

请解释一下区别。

【问题讨论】:

    标签: scala function scala-cats


    【解决方案1】:

    您的两个List 示例都可以编译,但它们的含义不同,也不会产生相同的结果。

    e.map(i => List(i2s(i))) //res0: scala.util.Either[String,List[String]] = Right(List(10))
    e.map(List(i2s(_)))      //java.lang.IndexOutOfBoundsException: 10
    

    第一个很容易理解,那么第二个是怎么回事?

    发生的情况是您正在使用 eta expansioni2s() 方法创建一个 Int => String 函数。然后,您使用该单个函数作为列表中唯一的元素填充 List,然后尝试检索索引 10 处的值,该值不存在,因此出现异常。

    如果您将第一行更改为val e = 0.asRight[String],那么异常就会消失,因为在索引0 处存在确实的东西,即刚刚放入其中的函数。

    这是因为 List 实例将接受 Int 作为参数(通过隐藏的 apply() 方法),但 Option instance 没有 apply()采用Int (*) 的方法,因此无法编译。

    (*) Option 对象确实有一个 apply() 方法,但那是另一种动物。

    【讨论】:

      【解决方案2】:

      关于为什么您的第一个 List[A] 示例有效,这里有多种原因。首先,让我们看一下表达式上发生的扩展:

      val res: Either[String, Int => String] = 
        e.map[Int => String](List.apply[Int => String](((x$1: Int) => FlinkTest.this.i2s(x$1))));
      

      注意两点:

      • lambda 表达式的扩展发生在inside List.apply,可能与您预期的不同,因为它位于List.apply 之外,如下所示:

        e.map(i => List(i2s(i))
        
      • .map 的返回类型不知何故不是Either[String, List[Int => String]],而是Either[String, Int => String]。这是因为在它的层次结构链中,List[A] 扩展了PartialFunction[Int, A],因此允许它把结果转换成一个函数类型。

      这不适用于Option[A],因为它不会在其类型层次结构中的任何地方扩展PartialFunction

      这里的关键点是 lambda 表达式的扩展不能像您预期的那样工作,因为 List(i2s(_)) 扩展为 List(i2s(x => i2s(x)) 而不是 List(i => i2s(i))。有关下划线扩展的更多信息,请参阅What are all the uses of an underscore in Scala?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-04-13
        • 2021-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-29
        • 1970-01-01
        相关资源
        最近更新 更多