2013-08-08 2 views
5

우리는 종종 액션을 수행하는 사용자와 같은 코드 컨텍스트 정보를 전달해야합니다. 권한 부여 검사와 같은 다양한 작업에이 컨텍스트를 사용합니다. 이러한 경우 암묵적인 값은 보일러 플레이트 코드를 줄이는 데 매우 유용 할 수 있습니다. Akka 배우 만 작업 할 때 패턴 일치에서 스칼라 암시 적 추출 값?

def onlyAdmins(f: => T)(implicit context:EC) = context match{ 
    case EC(u) if(u.roles.contain(Role.ADMIN)) => f 
    case _ => throw new UnauthorizedException("Only admins can perform this action") 
} 

val result = onlyAdmins{ 
    //do something adminy 
} 

나는 최근 자신이 작업을 수행 할 필요가에서 발견 case class EC(initiatingUser:User)

우리가 가질 수있는 편리한 가드 :

의 우리가 우리 주위에 통과 간단한 실행 컨텍스트 있다고 가정 해 봅시다 그들은 패턴 매칭 (pattern matching)을 사용하고 있으며, 아직 추출기 (extractor)와 함축 된 implicits를 만드는 좋은 방법을 찾고 있습니다.

먼저 당신은 모든 명령 컨텍스트를 통과해야하지만 간단합니다 :

case class DeleteCommand(entityId:Long)(implicit executionContext:EC) 
//note that you need to overwrite unapply to extract that context 

하지만 기능은 다음과 같습니다 나타납니다

class MyActor extends Actor{ 
    def receive = { 
    case DeleteCommand(entityId, context) => { 
     implicit val c = context 
     sender ! onlyAdmins{ 
     //do something adminy that also uses context 
     } 
    } 
    } 
} 

그것은 추출 된 변수의 경우 훨씬 더 간단 것 암시 적으로 표시 될 수 있지만이 기능을 보지 못했습니다.

def receive = { 
    case DeleteCommand(entityId, implicit context) => sender ! onlyAdmins{ 
    //do something adminy (that also uses context) 
    } 
} 

Ar e를 코딩하는 대안적인 방법을 알고 있으므로 상용구 코드가 줄어 듭니다.

+0

당신이에 관심이있을 수는 : http://stackoverflow.com/questions/6156656/how-to-pattern-match-a-class-with-multiple-argument-lists – gzm0

+0

이 무엇 GADTs 같은 소리 typeclass context와 implicits의 유사성을 고려한다면 Haskell에서 할 수있다. 스칼라에서 GADT와 유사한 패턴 매칭을 수행하는 더 원칙적인 방법을 제공 할 수도 있습니다. –

답변

1

여러 개의 매개 변수 집합을 추가하고 사례 클래스에 implicits를 추가하고 새로운 unapply을 추가해야한다고 생각하는 것이 좋지 않은 경로를 따라 간다는 징후 일 수 있습니다. 이러한 유형의 것들이 가능하지만, 아마도 좋은 생각이 아니며, 케이스 클래스에 대한 다중 매개 변수 세트 (implicits)와 같은 것이 언젠가 사라질 수 있습니다. 저는 여러분의 모범을 좀 더 표준적인 것으로 약간 썼습니다. 나는 그것이 완벽한 해결책 말하는 게 아니에요,하지만 표준 경로 아래로 더 :

그것의 위해서
trait ContextCommand{ 
    def context:EC 
} 

case class DeleteCommand(entityId:Long, context:EC) extends ContextCommand 


def onlyAdmins[T](cmd:ContextCommand)(f: => T) = cmd.context match { 
    case EC(u) if(u.roles.contain(Role.ADMIN)) => f 
    case _ => throw new UnauthorizedException("Only admins can perform this action")  
} 

class MyActor extends Actor{ 
    def receive = { 
    case cmd @ DeleteCommand(entityId, ctx) => { 
     sender ! onlyAdmins(cmd){ 
     //do something adminy that also uses context 
     //Note, ctx available here via closure 
     } 
    } 
    } 
} 
+0

사례 클래스에 대한 두 번째 매개 변수 목록을 사용하는 것이 좋다고 생각했지만 implicits를 최대한 활용하려고했습니다. 실행 컨텍스트가이를 사용하는 완벽한 사용 사례 인 것 같습니다. 바로 그곳에 있어야 할 가치가 있습니다. 귀하의 예가 그것을하는 고전적인 방법이며, 아마도 나는 그것에 충실해야합니다. 이것은 기본적으로 Java에서 연령대에 따라 (또는 named _, ThreadLocal이 아니어야 함) 수행되었습니다. –

0

, 나는 그것을 취할 수 얼마나 멀리 볼 수있는 초기 접근 방식을 계속했습니다. 내가 함께 종료하는 경우에 유용 할 수 있습니다 : 내가 의도 한대로

abstract class ContextCommand[T]{ 
    def context: EC 
    def reply(sender:ActorRef)(f: EC => T) = sender.!(
    try f(context) 
    catch{ 
     case e:Throwable => translateExceptionToFailure(e) 
    } 
) 
} 
trait ActorCommons[T]{ 
    case class GetCommand(val entityId:Long)(implicit val context: EC) 
    extends ContextCommand[Option[T]] 
} 

그때 내가 응답 함수의 결과 유형-확인이라는 추가 혜택과 함께, 배우에서 사용할 수 있습니다.

object MyActor extends ActorCommons[MyClass] 
class MyActor extends Actor{ 
    import MyActor._ 
    def receive = { 
    case [email protected](entityId) => cmd.reply(sender){ implicit c => onlyAdmins{ 
     ... 
    }} 
    } 
}