2013-09-28 2 views
2

스칼라를 처음 사용하고 Unfiltered (http://unfiltered.databinder.net/Try+Unfiltered.html)의 예제에서 패턴 일치 구문의 구문을 이해하는 것은 처음입니다.스칼라/필터링되지 않음의 패턴 일치 구문

다음은 Hello World를 되 찾는 간단한 HTTP 서버입니다! 경로, 원세그에 대한

참조 또한
package com.hello 

import unfiltered.request.GET 
import unfiltered.request.Path 
import unfiltered.request.Seg 
import unfiltered.response.ResponseString 

object HelloWorld { 
    val sayhello = unfiltered.netty.cycle.Planify { 
    case GET(Path(Seg(p :: q :: Nil))) => { 
     ResponseString("Hello World! " + p + " " + q); 
    } 
    }; 

    def main(args: Array[String]) { 
    unfiltered.netty.Http(10000).plan(sayhello).run(); 
    } 
} 

소스 코드 및 GET/Method 객체 :

package unfiltered.request 

object Path { 
    def unapply[T](req: HttpRequest[T]) = Some(req.uri.split('?')(0)) 
    def apply[T](req: HttpRequest[T]) = req.uri.split('?')(0) 
} 

object Seg { 
    def unapply(path: String): Option[List[String]] = path.split("/").toList match { 
    case "" :: rest => Some(rest) // skip a leading slash 
    case all => Some(all) 
    } 
} 

class Method(method: String) { 
    def unapply[T](req: HttpRequest[T]) = 
    if (req.method.equalsIgnoreCase(method)) Some(req) 
    else None 
} 

object GET extends Method("GET") 

내가 할 수 있었다 및 경로 2 개 긴 부분 경로의 두 부분 인 경우 그것의 대부분이 어떻게 작동하는지 분석해 보라. 그러나이 선은 나를 당혹스럽게 만든다.

case GET(Path(Seg(p :: q :: Nil))) => { 

나는 코드의 목적을 이해하지만 어떻게 적용되는지는 알지 못한다. Scala의 기능을 배우는 것에 관심이 많습니다. 스칼라에 HTTP 서버를 구현하는 것보다는 스칼라의 기능을 배우는 데 많은 시간을 할애하고 있습니다. 나는 그것이 GET, PathSeg 개체 추출기와 unapply 방법을 함께 할 수있는 뭔가가 있음을 이해하고, 나 또한 내가 디버깅 할 때 Seg 전에 PathPath 전에 GET에서 unapply 안타 것을 알고있다.

나는 다음과 같은 것들을 이해하지 않는다 :

  1. 가 왜 GET.unapply(req) 기록 할 수 없습니다,하지만 난 GET(req) 또는 GET()을 쓸 수 있으며 모든 HTTP GET과 일치합니다?

  2. 각 추출기의 unapply 메서드에 어떤 값이 전달되는지 컴파일러가 왜 또는 어떻게 알 수 있습니까? 그것들 중 하나가 Some 대신에 None을 반환하지 않는 한 그것들은 함께 묶일 것입니까?

  3. 변수 p와 q를 어떻게 바인딩합니까? 그것들은 문자열이라는 것을 알기 때문에 반환 유형 Seg.unapply에서 유추해야하지만 목록의 첫 번째 부분의 값을 p에 지정하고 목록의 두 번째 부분의 값을 q 지정하는 메커니즘을 이해하지 못합니다.

  4. 무슨 일이 일어나고 있는지 명확하게하기 위해 다시 작성하는 방법이 있습니까? 이 예제를 처음 보았을 때, 나는 회선 val sayhello = unfiltered.netty.cycle.Planify {으로 혼란스러워했고, 다시 파고 다시 작성하여 암시 적으로 PartialFunction을 만들어 Planify.apply에 전달한다는 것을 알았습니다.

답변

2

이 표현식을 스칼라 컴파일러로 다시 작성하는 방식으로 다시 작성하는 것이 하나의 방법입니다.

unfiltered.netty.cycle.PlanifyPartialFunction[HttpRequest[ReceivedMessage], ResponseFunction[NHttpResponse]], 즉 인수와 일치하거나 일치하지 않을 수있는 함수를 필요로합니다. case 문 중 하나에 일치하는 항목이 없으면 요청이 무시됩니다. 일치가있는 경우 (모든 추출기를 통과해야 함) 응답이 반환됩니다.

case 문장의 인스턴스는 HttpRequest[ReceivedMessage]입니다.그런 다음, 정합 기의 각 unapply 방법의 일련의 왼쪽 연관성을 적용

// The request passed to us is HttpRequest[ReceivedMessage] 
// GET.unapply only returns Some if the method is GET 
GET.unapply(request) flatMap { getRequest => 
    // this separates the path from the query 
    Path.unapply(getRequest) flatMap { path => 
     // splits the path by "/" 
     Seg.unapply(path) flatMap { listOfParams => 
      // Calls to unapply don't end here - now we build an 
      // instance of :: class, which 
      // since a :: b is the same as ::(a, b) 
      ::.unapply(::(listOfParams.head, listOfParams.tail)) flatMap { case (p, restOfP) => 
       ::.unapply(::(restOfP.head, Nil)) map { case (q, _) => 
        ResponseString("Hello World! " + p + " " + q) 
       } 
      } 
     } 
    } 
} 

는 희망이 당신에게 일치하는이 장면 뒤에 작동하는 방법에 대한 아이디어를 제공합니다. 내가 완전히 :: 비트를 가지고 있다면 나는 잘 모르겠다 - 의견 환영합니다.