Scala:隐式消耗作为模式匹配一​​部分提取的变量

问题描述

给定一个这样的方法

def toFun()(implicit a: Box) = a.toCircle()

根据我的理解,目前,我们需要这样的语法:

anObject match {
  case Another(a,b,c,_) =>
   implicit val tempA = a
   toFun()
  case YetAnother(a,_) =>
   implicit val tempA = a
   toFun()
}

我们有更直观的语法吗?

anObject match {
  case Another(implicit a,_) =>
   toFun()
  case YetAnother(implicit a,_) =>
   toFun()
}

更新:

我知道我们可以这样做:

anObject match {
  case Another(a,_) =>
   toFun()(a)
  case YetAnother(a,_) =>
   toFun()(a)
}

但是对于像这样的方法

def toFun()(implicit a: Box,b: Size,c: Context) = a.toCircle()

需要执行以下操作,从而违背了隐式的目的:

def main = {
  implicit context =>
    anObject match {
        case Another(a,_) =>
         toFun()(a,context)
        case YetAnother(a,context)
     }
}

示例:

请注意 messageContext 及其用法

class Worker extends Actor {
    def receive = {
      case m: MessageContext =>
        /**
        *
        *   Notice this
        */
        implicit val messageContext = m

        processor.processMessage{
            conversation =>
                val lastMessage = conversation.chat.last
                lastMessage.message match {
                    case Some(text) =>
                        if (text.contains("/search")) {
                            val searchArgs = text.trim.split("/search")
                            if (searchArgs.nonEmpty) {
                                val query = searchArgs.last.trim
                                system.scheduler.scheduleOnce(1800 milliseconds) {
                                    val activeContent = s"""
                                    Some content"
                                    |""".stripMargin)
                                    conversation.activeContent = activeContent
                                    processor.reply(s"""
                                    |Here are search results for "${query}":
                                    |${activeContent.mkString("\n------------\n")}
                                    |
                                    |""".stripMargin)
                                }
                                s"""Hello ${conversation.user.firstName},we have received a search query for "${query}". We will soon respond with search results"""
                            } else {
                                s"""Hello ${conversation.user.firstName},please enter a keyword post search command,i.e. "/search keyword"!"""
                            }
                        } else if (text.contains("/remind")) {
                            if (conversation.activeContent.isEmpty) {
                                "Please /search something first"
                            } else {
                                val remindArgs = (allCatch opt(text.split("/remind").last.trim.toInt)) // .split(" ")
                                if (remindArgs.isDefined) {     
                                    system.scheduler.scheduleOnce(5000 milliseconds) {
                                        /**
                                        *
                                        *   The above implicit is used here,if I pass it as an argument,then I will needed to pass other implciit arguments as well
                                        *   If I pass message as a standard argument,then the reply method looses it's simplciity,and please do factor in that
                                        *   we will need to call it at n number of times as the conversation tree grows
                                        */
                                        processor.reply(s"""Here's the reminder after 5 seconds for resource: ${conversation.activeContent(remindArgs.get - 1)}""")
                                    }             
                                    s"Hello ${conversation.user.firstName},we would love to remind you about the resource: ${conversation.activeContent(remindArgs.get - 1)} "
                                } else {
                                    """Please enter valid index number,refer to search results. Use the number in begining of each search result item i.e. "/remind 1" or "/remind 2" or "/remind 5"!"""
                                }
                            }
                        } else {
                            conversation.activetopic match {
                                case Some(topic)=>
                                    topic match {
                                        case Goal =>
                                        "Some message..."
                                        case Changetopic =>
                                            if (List("yes","yeah","yo","yay","y","ya","yepp","why not").contains(text.toLowerCase.replace("!",""))) {
                                                system.scheduler.scheduleOnce(5000 milliseconds) {
                                                    /**
                                                    *
                                                    *   Notice this
                                                    *   
                                                    */
                                                    processor.reply(s"""Yeah,we can change the topic""")
                                                }
                                                "Let me think if we are done here"
                                            }
                                            else {
                                            "Some message..."
                                            }
                                        case .......
                                    }
                                case _ => s"No active topic out there! Would you like to /start again?"
                            }
                        }
                    case None =>
                        conversation.activetopic match {
                            case Some(topic)=>
                                topic match {
                                case GoalUploadPrompt =>
                                    lastMessage.raw.document match {
                                        case Some(doc) => doc.toString
                                        case None => lastMessage.raw.photo match {
                                            case Some(photo) => 
                                                "Some message..."
                                            case None => "Some message..."
                                        }
                                    }
                            case _ =>
                                "Some message..."
                            }
                            case None => "Some message...."
                        }
                }
            }(m,ws,token)
            case _ =>
        }
    }


object processor {
    def processMessage(cb: (BotConversation) => String)(implicit msg: MessageContext,ws: WSClient,token: String) = ?
}

解决方法

如评论中所述,您始终可以显式传递隐式参数。 这是一种可能性。

或者,先设置隐式,然后调用:

    implicit val (a,b) = foo match {
      case Something(a,b,_) => a -> b
      case Another(a,_) => a -> b
    }
    toFun()

或者,为了解决评论中提出的另一种可能性:

     case foo match {
        case DoNothing => 
        case _ => 
             implicit val (a,b) = foo match {
                 case Something(a,_) => a -> b
                 case Another(a,_) => a -> b
             }
             toFun()
     }

一般来说,您可以不断提出额外的复杂性,但在某些时候应该会变得很明显,如果您必须跳过这么多圈子以隐式提供您的值,那么也许,它们不应该真的首先是隐含的?