2015-03-10 3 views
3

Есть ли более элегантный способ сделать следующее?Scala: Сокращение для соответствия шаблону по типу?

data match { 
    case e: SomeType => doSomethingWith(e) 
    case _ => 
} 

Ищете что-то вроде:

data.ifInstanceOf[SomeType](doSomethingWith) 
+3

Ух, это должно быть сложнее, не проще. –

+0

Вполне возможно, что существует лучший способ использования полиморфизма. С другой стороны, в этом случае SomeType является mixin –

ответ

3

По какой-то причине это не придумали:

import PartialFunction._ 

condOpt("abc": Any) { case s: String => s.length } // = Some(3) 
condOpt((): Any) { case s: String => s.length } // = None 

Я обычно переименовать его или его брата cond к when.

+0

Спасибо - это хорошо работает для меня –

+0

Редактор, который сказал, что формат REPL лучше, был прав. Вы можете вырезать/вставить стенограмму непосредственно в REPL. Однако вы не можете сохранить сеанс (который даст вам только LOC). https://issues.scala-lang.org/browse/SI-9214 –

1

Вы можете использовать asInstanceOf, чтобы получить цель:

Option(data) 
    .filter(_.isInstanceOf[SomeType]) 
    .map(_.asInstanceOf[SomeType]) 
    .map(doSomethingWith) 

, но я предполагаю, что это слишком многословным.

+0

Целью является применение функции, если тип соответствует 'T', а не для перевода в' T', а затем применить. – Marth

+0

@Marth Ваше решение является scala идиоматическим способом. Не пытайтесь найти лучше –

+0

Я не был тем, кто задал этот вопрос, и я согласен с тем, что оригинальное предложение - лучший способ сделать то, что он хочет. Я просто указываю, что ваше решение семантически отличается от вашего: ваш будет применять 'doSomethingWith' независимо от того, является ли' data' 'SomeType', тогда как его не будет. – Marth

4

Вы хотите выражение или просто выполнить побочный эффект? Если это просто побочный эффект с помощью «PimpMyLibrary» подход + трапезу:

import scala.reflect.ClassTag 

    implicit class AnyOps(data : Any) { 
    def ifInstanceOf[A : ClassTag](f: A => Unit) : Unit = { 
     val clzz = implicitly[ClassTag[A]].runtimeClass 
     if (clzz.isInstance(data)) f(data.asInstanceOf[A])  
    } 
    } 

Вы можете попробовать

"abc".ifInstanceOf[String](println) 
"def".ifInstanceOf[Integer](println) 
1.ifInstanceOf[Integer](println) 
2.ifInstanceOf[String](println) 

Если вы хотите выражение, которое я считаю, что лучший способ пойти, чтобы добавить дополнительный тип Параметр B и возврат Либо [B, Anyref].

+0

Шаблон-шаблон будет использовать ваш ClassTag: 'неявный класс AnyOps (data: Any) {def as [A: ClassTag] (f: A => Any) = соответствие данных {case a: A => f (a) case _ = >}} ' –

4

Я думаю, что collect может работать для этого. Метод принимает частичную функцию, и отфильтровывает элементы, которые не соответствуют никаким case заявления:

Option(data) collect { 
    case element: SomeType => mappingFunction(element) 
} 

Конечно, mappingFunction здесь может иметь побочные эффекты и вернуть Unit, тем самым имитируя foreach.

Если вы хотите создать новый метод с именем, вы могли бы сделать новый метод на Any:

implicit class AnyOps(data: Any) { 
    def forMatch[A](pf: PartialFunction[Any, A]) = pf.lift(data) 
} 
+0

Как будет собирать работу? 'data' может быть любым классом, который не должен иметь метод сбора, определенный на нем. – mohit

+1

@mohit sorry Я забыл обернуть 'data' в' Option', чтобы у вас был метод 'collect'. Исправлено. –

0

Я думаю, вы найдете его трудно найти что-либо более короткий или более точным, чем «старый добрый» ...

if (data.isInstanceOf[SomeType]) doSomething(data) 

... если ваш случай не является более сложным, чем вы показываете

+0

В приведенном выше примере не было бы doSomething (data) doSomething (data.asInstanceOf [SomeType])? –

+0

Вы абсолютно правы; что уменьшит полезность, когда вам понадобится этот тип в качестве входных данных; что вполне вероятно. – thoredge

Смежные вопросы