2010-08-03 5 views
75

Was sind Paketobjekte, nicht so sehr das Konzept, sondern ihre Verwendung?Paketobjekte

Ich habe versucht, ich ein Beispiel zum Laufen zu bringen und die einzige Form war zur Arbeit bekam wie folgt:

package object investigations { 
    val PackageObjectVal = "A package object val" 
} 

package investigations { 

    object PackageObjectTest { 
     def main(args: Array[String]) { 
      println("Referencing a package object val: " + PackageObjectVal) 
     } 
    } 
} 

Observations ich sind bisher gemacht habe:

package object _root_ { ... } 

nicht zulässig ist (was vernünftig ist),

package object x.y { ... } 

ist ebenfalls nicht erlaubt.

Es scheint, dass ein Paketobjekt im unmittelbar übergeordneten Paket deklariert werden muss und, falls wie oben beschrieben, das klammergetrennte Paketdeklarationsformular erforderlich ist.

Werden sie häufig verwendet? Wenn das so ist, wie?

+6

http://www.naildrivin5.com/scalatour/wiki_pages/PackageObjects – oluies

+1

@Brent, das ist eine großartige Ressource, nicht nur für den Paketobjektartikel. Ich habe von dem Autor gehört, wusste aber nicht, dass er diese Scala-Tour geschrieben hat, danke. –

Antwort

113

Normalerweise würden Sie Ihr Paket Objekt in einer separaten Datei mit dem Namen in dem Paket package.scala setzen, die es entspricht. Sie können auch die Syntax des verschachtelten Pakets verwenden, aber das ist ziemlich ungewöhnlich.

Der Hauptanwendungsfall für Paketobjekte ist, wenn Sie Definitionen an verschiedenen Stellen innerhalb Ihres Pakets sowie außerhalb des Pakets benötigen, wenn Sie die vom Paket definierte API verwenden. Hier ein Beispiel:

// file: foo/bar/package.scala 

package foo 

package object bar { 

    // package wide constants: 
    def BarVersionString = "1.0" 

    // or type aliases 
    type StringMap[+T] = Map[String,T] 

    // can be used to emulate a package wide import 
    // especially useful when wrapping a Java API 
    type DateTime = org.joda.time.DateTime 

    type JList[T] = java.util.List[T] 

    // Define implicits needed to effectively use your API: 
    implicit def a2b(a: A): B = // ... 

} 

nun die Definitionen innerhalb dieses Pakets Objekt sind innerhalb des gesamten Pakets foo.bar zur Verfügung. Außerdem werden die Definitionen importiert, wenn jemand außerhalb dieses Pakets foo.bar._ importiert.

Auf diese Weise können Sie verhindern, dass der API-Client zusätzliche Importe ausgibt, um Ihre Bibliothek effektiv zu verwenden - z. in scala-Schaukel benötigen Sie

import swing._ 
import Swing._ 

haben alle die Güte wie onEDT und implizite Konvertierungen Tuple2-Dimension zu schreiben.

+12

Vorsicht: Überladen von Methoden funktioniert nicht in Paketobjekten. – retronym

+0

Beats me, warum gewählt wurde, dass das Paketobjekt eine Ebene höher als die Pakethierarchie definiert werden sollte. Z.B. Das bedeutet, dass Sie das Paket mit der obersten Ebene der virtuellen 'org' oder' com' mit Ihrem Paketobjekt verschmutzen müssen, wenn Sie möchten, dass es zu Ihrem eigenen root-Paket gehört, z. 'org.foo'. Ich finde, dass die Definition direkt unter dem Paket sein kann, sollte es ein Teil von sein - wäre etwas passender Sprache API Schnittstelle gewesen. – matanster

7
+0

@Alex Cruise, danke, das scheint darauf hinzudeuten, dass sie eine separate Kompilierungseinheit benötigen (die sich vielleicht um die durch Klammer begrenzte Paketbeschränkung herum erstreckt). Das Problem ist, dass ich einen soliden Benutzerrat brauche und nicht meine eigene Vermutung, wie man sie benutzt. –

51

Während die Antwort von Moritz genau richtig ist, ist zu beachten, dass Paketobjekte Objekte sind. Dies bedeutet unter anderem, dass Sie sie mithilfe von Mix-In-Vererbung aus Merkmalen erstellen können. Moritz Beispiel könnten geschrieben werden als

package object bar extends Versioning 
          with JodaAliases 
          with JavaAliases { 

    // package wide constants: 
    override val version = "1.0" 

    // or type aliases 
    type StringMap[+T] = Map[String,T] 

    // Define implicits needed to effectively use your API: 
    implicit def a2b(a: A): B = // ... 

} 

Hier Versionierung ist eine abstrakte Eigenschaft, die besagt, dass das Paket Objekt eine „Version“ Methode haben muss, während JodaAliases und JavaAliases Beton sind Merkmale enthalten, praktisch Typ Aliase. Alle diese Eigenschaften können von vielen verschiedenen Paketobjekten wiederverwendet werden.

+0

Das ganze Thema öffnet sich viel und es scheint sein volles Potenzial zu nutzen, danke für ein weiteres reiches Beispiel. –

+1

aber sie können nicht als Vals verwendet werden, also sind sie nicht wirklich Objekte –