2012-06-27 8 views
11
sealed class A 
class B1 extends A  
class B2 extends A 

Supponendo che abbiamo un elenco di oggetti di classe A: val l: Lista [A] = List (nuova B1, nuova B2, nuova B1, nuova B1)Quando usare isInstanceOf e quando usare un'istruzione match-case (in Scala)?

E vogliamo filtrare il elementi del tipo B1. Poi abbiamo bisogno di un predicato e potrebbero utilizzare i seguenti due alternative:

l.filter(_.isInstanceOf[B1]) 

O

l.filter(_ match {case b: B1 => true; case _ => false}) 

Personalmente, mi piace il primo approccio di più, ma ho letto spesso, si dovrebbe utilizzare l'istruzione match-case più spesso (per ragioni che non conosco).

Pertanto, la domanda è: ci sono degli svantaggi nell'uso di isInstanceOf invece della dichiarazione match-case? Quando si dovrebbe usare quale approccio (e quale approccio dovrebbe essere usato qui e perché)?

risposta

17

È possibile filtrare così:

l.collect{ case x: B1 => x } 

che è molto più leggibile, IMO.

+3

E ti dà il tipo più stretto alla fine ('Elenco [B1]'). –

+0

Sembra molto più leggibile, grazie.Ma quale sarà il caso predefinito in questa affermazione? Dove posso leggere ulteriori informazioni di base su questa dichiarazione del caso di scelta rapida e su come viene utilizzata? –

+0

@JohnThreepwood dai un'occhiata a [questo post] (http://ochafik.com/blog/?p=393). Non è il massimo, ma è comunque molto buono "il perché di raccogliere". In breve, raccogli è come una mappa, ma crea un lavoro solo per quei valori che sono definiti per la funzione * (parziale) * che passi a questo metodo. La corrispondenza del modello di Scala in questo caso viene eseguita in [PartialFunction] (http://stackoverflow.com/questions/5668053/scala-partial-functions). Inoltre, è necessario utilizzare parentesi graffe. –

7

Non ci sono alcuna differenza

gatto t.scala:

class A { 
    def x(o: AnyRef) = o.isInstanceOf[A] 
    def y(o: AnyRef) = o match { 
    case s: A => true 
    case _ => false 
    } 
} 

$ scalac -print t.scala

[[syntax trees at end of cleanup]]// Scala source: t.scala 
package <empty> { 
    class A extends java.lang.Object with ScalaObject { 
    def x(o: java.lang.Object): Boolean = o.$isInstanceOf[A](); 
    def y(o: java.lang.Object): Boolean = { 
     <synthetic> val temp1: java.lang.Object = o; 
     temp1.$isInstanceOf[A]() 
    }; 
    def this(): A = { 
     A.super.this(); 
    () 
    } 
    } 
} 
+0

Grande, grazie per le informazioni di base che cosa farà il compilatore di scala. –

9

Il vantaggio di match-case è che non si fa devi lanciare l'oggetto nel caso in cui tu voglia eseguire operazioni su di esso che dipendono dal suo tipo più stretto.

nel seguente frammento, usando isInstanceOf sembra essere bene perché non si esegue tale operazione:

if (obj.isInstanceOf[A]) println(obj) 

Tuttavia, se si fa la seguente:

if (obj.isInstanceOf[A]) { 
    val a = obj.asInstanceOf[A] 
    println(a.someField) // someField is declared by A 
} 

poi ho' d essere favorevole all'utilizzo di match-case:

obj match { 
    case a: A => println(a.someField) 
    case _ => 
} 

È leggermente fastidioso ing che si deve includere il "altrimenti" CAUSA, ma usando collect (come suggerito da om-nom-nom) potrebbe aiutare, almeno se si lavora con le collezioni ereditare da Seq:

collectionOfObj.collect{ case a: A => a}.foreach(println(_.someField)) 
+0

Grazie per i tuoi buoni esempi, molto bello. –

9

Non c'è problema utilizzando isInstanceOf, fino a quando non si utilizza asInstanceOf.

Il codice che utilizza entrambi è fragile, perché il controllo e il cast sono azioni separate, mentre usando l'abbinamento si ha una singola azione facendo entrambe le cose.

+0

Grazie per il suggerimento, guarderò per quello. –