Scala语法说明,涉及高阶函数,类型参数和返回类型

时间:2018-08-19 10:16:44

标签: scala types syntax parameters explain

我在理解Scala语法时遇到问题,请提出建议。我有两个代码片段。

abstract class Try[T] {

  def flatMap[U](f: T => Try[U]): Try[U] = this match {
    case Success(x) => try f(x) catch { case NonFatal(ex) => Failure(ex) }
    case fail: Failure => fail
  }
}

我的理解:

  • flatMap作为函数f接收作为参数。反过来这个功能f 接收类型参数T并返回类型参数U的Try。
  • flatMap最终返回类型参数U的Try。

Q1-我的理解正确吗?

Q2-f的返回类型(即Try [U])和平面映射Try [U]的返回类型之间有什么关系?一定要一样吗?

  

def flatMap [U](f:T => Try [U] ): Try [U]

或者我可以以某种方式拥有类似的东西

  

def flatMap [U](f:T => Option [U] ):尝试[U]

在最后一段代码中,我猜想,在我的flatMap中使用函数f之后,我需要在f的输出(即Option [U])和flatMap要求的最终输出之间建立连接。 (我是说Try [U])

  

编辑

此代码来自一个scala课程。这是完整的代码(有人问了这个问题)。我只想了解语法。

abstract class Try[T] {

def flatMap[U](f: T => Try[U]): Try[U] = this match {
    case Success(x) => try f(x) catch { case NonFatal(ex) => Failure(ex) }
    case fail: Failure => fail
}

def map[U](f: T => U): Try[U] = this match {
    case Success(x) => Try(f(x))
    case fail: Failure => fail
}
}

2 个答案:

答案 0 :(得分:0)

Q1 在很大程度上是正确的,但只是为了澄清,所有这些都在编译时发生-T在运行时未知(请参见here

第二季度当然,您可以创建带有签名的方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ERL.Models
{
    public class LabEntry
    {
        public int sl { get; set; }
        public string unitname { get; set; }
        public string SampleName { get; set; }
        public DateTime Entrydate { get; set; }
        public string EntryTime { get; set; }
        public string userid { get; set; }
        public decimal Density15C { get; set; }
        public decimal RVP_PSI { get; set; }
        public string colourASTM { get; set; }
        public decimal FP { get; set; }
        public decimal Viscosity50 { get; set; }
        public decimal Viscosity100 { get; set; }
        public decimal pp { get; set; }
        public decimal ASTM_IBP { get; set; }
        public decimal ASTM5 { get; set; }
        public decimal ASTM10 { get; set; }
        public decimal ASTM50 { get; set; }
        public string ASTM90 { get; set; }
        public string ASTM95 { get; set; }
        public decimal FBP { get; set; }
        public decimal BSWB4Oxid { get; set; }
        public decimal BSWAfterOxid { get; set; }
        public string Report { get; set; }
        public decimal FR5xylene { get; set; }
        public int slWater { get; set; }
        public string SampleNameWater { get; set; }
        public decimal ph { get; set; }
        public decimal COND { get; set; }
        public decimal TDS { get; set; }
        public decimal TA { get; set; }
        public decimal TAC { get; set; }
        public decimal NACL { get; set; }
        public decimal H2S { get; set; }
        public decimal NH3 { get; set; }
    }
}

您可以随意调用该方法flatMap,但它不是标准的flatMap:

 override func viewWillAppear(_ animated: Bool) {
    let textFieldInsideSearchBar = searchBar.value(forKey: "_searchField") as? UITextField
    textFieldInsideSearchBar?.borderStyle = .none
    textFieldInsideSearchBar?.textColor = UIColor.white
    textFieldInsideSearchBar?.underlined()
}

flatMap的形式存在数学原因(这也对Scala的for表达式的实现有影响)。为避免混乱...

...[U](f: T => Option[U]): Try[U] trait T[A] { flatMap[B](f: A => T[B]): T[B] } 包裹起来,以创建T => Option[U] ,然后再将其传递给flatMap,而不是更改flatMap的签名。

答案 1 :(得分:0)

  

Q1-我的理解正确吗?

很难根据您的示例代码进行注释,该示例代码在抽象类中具有方法实现,而未定义任何具体类。让我们考虑从Scala API中提取的Try的以下玩具版本,并在其具体类中使用flatMap实现:

import scala.util.control.NonFatal 

sealed abstract class MyTry[+T] {
  def flatMap[U](f: T => MyTry[U]): MyTry[U]
}

object MyTry {
  def apply[T](r: => T): MyTry[T] =
    try MySuccess(r) catch { case NonFatal(e) => MyFailure(e) }
}

final case class MyFailure[+T](exception: Throwable) extends MyTry[T] {
  override def flatMap[U](f: T => MyTry[U]): MyTry[U] =
    this.asInstanceOf[MyTry[U]]
}

final case class MySuccess[+T](value: T) extends MyTry[T] {
  override def flatMap[U](f: T => MyTry[U]): MyTry[U] =
    try f(value) catch { case NonFatal(e) => MyFailure(e) }
}

使用以下函数f: T => MyTry[U]对其进行测试,其中T =字符串,U =整数,希望它能回答您的问题:

val f: String => MyTry[Int] = s => s match {
  case "bad" => MyFailure(new Exception("oops"))
  case s => MySuccess(s.length)
}

MyTry("abcde").flatMap(f)
// res1: MyTry[Int] = MySuccess(5)

MyTry("bad").flatMap(f)
// res2: MyTry[Int] = MyFailure(java.lang.Exception: oops)
  

Q2-f的返回类型(即Try [U])之间的关系是什么   以及平面地图Try [U]的返回类型?一定要一样吗?

在Scala中,flatMap是许多Scala容器/集合中定义的常用方法,例如Option[T]List[T]Try[T]Future[T],标准签名:

class Container[T] {
  def flatMap[U](f: T => Container[U]): Container[U]
}

如果您想要一个特殊的地图,该地图需要一个T => Container1[U]函数并返回一个Container2[U],则最好不要将其命名为flatMap