패키지 개체


92

개념이 아니라 사용법이 아닌 패키지 객체는 무엇입니까?

나는 작동하는 예제를 얻으려고 노력했고 내가 일해야 할 유일한 양식은 다음과 같습니다.

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)
        }
    }
}

지금까지 관찰 한 내용은 다음과 같습니다.

package object _root_ { ... }

허용되지 않음 (합리적 임)

package object x.y { ... }

또한 허용되지 않습니다.

패키지 객체는 직계 부모 패키지에 선언되어야하며, 위와 같이 작성하면 중괄호로 구분 된 패키지 선언 양식이 필요합니다.

그들은 일반적으로 사용됩니까? 그렇다면 어떻게?



1
@Brent, 이것은 패키지 개체 기사뿐만 아니라 훌륭한 리소스입니다. 저자에 대해 들어 봤지만 그가이 Scala 투어를 작성했다는 사실을 몰랐습니다. 감사합니다.
Don Mackenzie

답변:


128

일반적으로 패키지 객체를 package.scala해당하는 패키지에서 호출되는 별도의 파일에 넣습니다 . 중첩 된 패키지 구문을 사용할 수도 있지만 이는 매우 드문 경우입니다.

패키지 객체의 주요 사용 사례는 패키지에서 정의한 API를 사용할 때 패키지 내부 및 패키지 외부의 다양한 위치에서 정의가 필요한 경우입니다. 다음은 예입니다.

// 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 = // ...

}

이제 해당 패키지 개체 내의 정의를 전체 패키지 내에서 사용할 수 있습니다 foo.bar. 또한 해당 패키지 외부의 누군가가 가져올 때 정의를 가져옵니다 foo.bar._.

이렇게하면 API 클라이언트가 라이브러리를 효과적으로 사용하기 위해 추가 가져 오기를 실행하도록 요구하지 않도록 할 수 있습니다. 예를 들어 scala-swing에서 작성해야합니다.

import swing._
import Swing._

에서 로의 모든 선함 onEDT과 암시 적 변환 을 갖 Tuple2습니다 Dimension.


13
주의 사항 : 메서드 오버로딩은 패키지 개체에서 작동하지 않습니다.
retronym

패키지 객체가 패키지 계층 구조에서 한 수준 위로 정의되어야하는 이유가 저를 압도합니다. 예를 들어 . 예를 들어 자신의 루트 패키지에 속하려면 패키지 객체로 가상 org또는 com최상위 패키지 를 오염시켜야합니다 org.foo. 정의가 포함되어야하는 패키지 바로 아래에있는 정의를 허용하는 것이 약간 더 적절한 언어 API 인터페이스 였을 것입니다.
matanster

58

Moritz의 대답이 자리 잡았지만 주목할 추가 사항은 패키지 객체가 객체라는 것입니다. 무엇보다도 이것은 믹스 인 상속을 사용하여 트레이 트로부터 그것들을 구축 할 수 있음을 의미합니다. Moritz의 예는 다음과 같이 쓸 수 있습니다.

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 = // ...

}

여기서 버전 관리는 추상적 인 특성으로 패키지 객체에는 "버전"메서드가 있어야하며 JodaAliases 및 JavaAliases는 편리한 유형 별칭을 포함하는 구체적인 특성입니다. 이러한 모든 특성은 다양한 패키지 객체에서 재사용 할 수 있습니다.


전체 주제가 많이 열리고 있으며 또 다른 풍부한 예 덕분에 잠재력을 최대한 발휘하는 데 익숙한 것 같습니다.
Don Mackenzie

1
하지만 정말 오브젝트 그들은 발스으로 사용할 수 없습니다, 그래서 그들은있어
에두아르도 파레 Tobes을

7

@Alex Cruise, 감사합니다. 이것은 별도의 컴파일 단위가 필요하다는 것을 암시하는 것 같습니다 (중괄호로 구분 된 패키지 제한을 반올림 할 수 있음). 문제는 사용 방법에 대한 내 자신의 추측보다는 확실한 사용자 조언을 원한다는 것입니다.
Don Mackenzie

5

패키지 객체의 주요 사용 사례는 패키지에서 정의한 API를 사용할 때 패키지 내부 및 패키지 외부의 다양한 위치에서 정의가 필요한 경우입니다.

그리로 스칼라 3 , 중간-2020 출시 될 예정 에 따라 도티 로, 여기에서 :

최상위 정의

모든 종류의 정의를 최상위에 작성할 수 있습니다.
패키지 개체는 더 이상 필요하지 않으며 단계적으로 제거됩니다.

package p 

type Labelled[T] = (String, T) 
val a: Labelled[Int] = ("count", 1) 
def b = a._2 
def hello(name: String) = println(i"hello, $name)

@VonC에게 감사드립니다. 저는 이것과 다른 많은 이유로 스칼라 3를 정말로 고대하고 있습니다. 나는 패키지 객체를 많이 사용하지는 않았지만 최상위 정의를 사용할 것이라고 확신합니다.
Don Mackenzie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.