2011-11-09 16 views
12

sto iniziando con Scala e l'ho trovato un po 'strano. In java avrei potuto fare qualcosa di simile:Perché le classi che non estendono altre classi devono estendersi dai tratti? (con non funziona)

interface Foo{} 

public class Bar implements Foo{} 

che sto cercando di fare qualcosa di simile con la Scala, ma non funziona:

trait Foo; 
class Bar with Foo; // This doesn't work! 

devo usare il "estende" parola chiave :

Ora, va bene, ma non è quello che volevo.

Un'altra cosa strana ho notato è che, data ogni classe a Scala si estende da AnyRef (vedi questa immagine da scala-lang.org: http://www.scala-lang.org/sites/default/files/images/classhierarchy.png) posso fare questo:

class Bar extends AnyRef with Foo; // This works too! 

Allora, che cosa mi manca ? Non ha senso usare un tratto senza estenderlo?

Grazie!

risposta

21

prima nota che la estende/implementa differenza dice nulla al compilatore di quanto non saprebbe. Non intendo che sia cattivo, solo che la lingua avrebbe potuto fare diversamente. In C#, si scrive class A : B, C, D anziché class A extends B implements C, D e class A implements B, C, D. Quindi puoi solo pensare che lo extends di Scala è come i due punti e with come la virgola.

Eppure, ai vecchi tempi, era class Bar with Foo. È cambiato quando Scala è tornato 2.0 nel 2006. Vedi the change history.

Penso di ricordare (non sono sicuro) che il motivo era semplicemente che class Bar with Foo non legge bene.

In Scala, A with B è l'intersezione dei tipi A e B. Un oggetto è di tipo A with B se è di tipo A e di tipo B. Quindi class A extends B with C può essere letto class A estende il tipo B with C. Non esiste nulla del genere con class A with B.

+0

Buona spiegazione, grazie! – santiagobasulto

3

Programming in Scala (2nd ed) discute tratti in Capitolo 12. Prende atto per quanto riguarda il extends:

È possibile utilizzare la parola chiave extends a mescolare in un tratto; in tal caso è possibile ereditare implicitamente la superclasse del tratto da . Ad esempio, nel Listato 12.2, classe sottoclasse AnyRef (la superclasse Philosophical) e mescola in Philosophical.

(Qui, Philosophical è un tratto.)

Quindi, il tuo ragionamento è esattamente corretto.

In tema di AnyRef, è necessario leggere su Scala class hierarchy e top types. (AnyRef non è il tipo superiore ma è abbastanza vicino.)

+0

Ho quel libro! Perché mi è mancato? Grazie @Emil – santiagobasulto

8

Se provieni da Java, può sembrare strano all'inizio (era lo stesso per me), ma in realtà ora trovo che sia più sintassi normale quindi Java, dove ho bisogno di dire esplicitamente se voglio implement o extend altra classe/interfaccia. Ma penso che sia più una questione di gusti personali.

In realtà non importa se si sta dicendo extends o implements. Entrambi rappresentano lo stesso tipo di relazione tra due cose: è un (a differenza di delega e composizione, che rappresentano ha una relazione). Qui, per esempio, è possibile trovare un po 'di informazioni su di esso:

http://www.javacamp.org/moreclasses/oop/oop5.html

Basta provare a sostituire extends, implements, with con is a e diventa più chiaro.

In Scala si hanno anche altre varianti della relazione is a. Per esempio tipi di auto:

trait Bar { 
    self: Foo => 
    // ... 
} 

Con questo che stai dicendo, che Bar non si estende/implementa Foo direttamente, ma tutte le altre classi, che vogliono estendere Bar dovrebbe anche estendere Foo.

I tipi di auto possono consentire cose interessanti. Per esempio due classi/caratteristiche che dipendono l'uno dall'altro:

class Bar extends Foo { 
    def sayHello(name: String) = println("Hello, " + name) 

    greet() 
} 

trait Foo { 
    this: Bar => 

    def greet() = sayHello("User") 
} 

new Bar() // prints: Hello, User 
+0

vedi anche http://www.levinotik.com/2012/09/14/scala-abstract-classes-traits-and-self-types/ – ZiglioUK

+0

questa è una risposta interessante, specialmente i "self types" parte. Grazie! – asgs

Problemi correlati