Scala には、すべてのインスタンスをメインで作成する方法があります。
たとえば、著者、ページ、本というクラスがあります。主に、これら 3 つのクラスのインスタンスを作成します。Book のインスタンスでは、ライターとページを配置します。
次に、どの本にも属さないページがあるかどうかを確認したいと思います。
例は単なる説明であり、あまり重要視しないでください。
皆さん、ありがとうございました。悪い英語の翻訳で申し訳ありません。
Scala には、すべてのインスタンスをメインで作成する方法があります。
たとえば、著者、ページ、本というクラスがあります。主に、これら 3 つのクラスのインスタンスを作成します。Book のインスタンスでは、ライターとページを配置します。
次に、どの本にも属さないページがあるかどうかを確認したいと思います。
例は単なる説明であり、あまり重要視しないでください。
皆さん、ありがとうございました。悪い英語の翻訳で申し訳ありません。
簡単な答え: いいえ、これを行う完全に自動化された方法はありません。割り当てられたすべてのオブジェクトを反復処理する必要があります。これはガベージ コレクターで実行できますが、プログラム自体では実行できません。
以下は、どのサブオブジェクトがルート オブジェクトにアタッチされているかを追跡する1 つの可能な方法のスケッチです。
サブオブジェクトとルートオブジェクトを区別できるようにする基本的な特性を定義します。
trait Root
trait Sub {
def register(r: Root)
def deregister(r: Root)
def isRegistered: Boolean
}
Book
次に、ページを追加できるルート オブジェクトを定義します。
class Book(val title: String) extends Root {
private var pages: Set[Page] = Set()
Books.books += this
def add(p: Page) {
pages += p
p.register(this)
}
def remove(p: Page) {
pages -= p
p.deregister(this)
}
}
インスタンス化の際、各ブックはグローバル リポジトリに追加されます。
object Books {
var books: Set[Book] = Set()
}
サブオブジェクトについても同様Page
:
class Page(number: Int) extends Sub {
private var owner: Option[Root] = None
Pages.pages += this
def register(r: Root) = owner match {
case None =>
owner = Some(r)
case Some(o) =>
sys.error("%s is already owned by %s, thus it cannot be owned by %s"
.format(this, o, r))
}
def deregister(r: Root) = owner match {
case Some(s) if r == s =>
owner = None
case Some(s) =>
sys.error("%s is owned by %s, but not by %s"
.format(this, s, r))
case None =>
sys.error("%s is not owned at all, thus also not by %s"
.format(this, r))
}
def isRegistered = owner.nonEmpty
}
object Pages {
var pages: Set[Page] = Set()
def allRegistered = pages.forall(_.isRegistered)
}
いくつかの使用例:
val p1 = new Page(1)
val p2 = new Page(2)
val p3 = new Page(3)
val b1 = new Book("Fahrenheit 451")
val b2 = new Book("Brave New World")
b1.add(p1)
b1.add(p2)
b2.add(p3)
println(Pages.allRegistered) // true
val p4 = new Page(4)
println(Pages.allRegistered) // false
b2.add(p4)
b2.remove(p3)
println(Pages.allRegistered) // false
b2.add(p1) // Exception: already owned
注:心に留めておくべき設計上の決定、未解決の問題:
サブオブジェクトを破棄する場合はどうすればよいですか? グローバル リポジトリから削除しますか?
サブオブジェクトを複数のルート オブジェクトが所有できますか?
複数の非グローバルリポジトリを用意した方がよいでしょうか? これはおそらく、サブオブジェクトを作成して登録するためのファクトリが必要であることを意味します。
同時設定では、(グローバル) リポジトリへのアクセスを同期する必要があります
サブオブジェクトを登録 (登録解除) するためのコードを単一のトレイトに移動し、それをすべてのルート オブジェクトで再利用できますか?
注 II:バックポインターがあれば、(グローバル) サブオブジェクト リポジトリのみが必要になります。ただし、組み込みのバックポインターを提供する言語は知りません。
あなたはできる
// If you use the REPL, :paste both class and object together
class Page {
Page.everything += this
var booked: Option[Book] = None // Or just set to null
}
object Page {
val everything: collection.mutable.HashSet[Page] = collection.mutable.HashSet()
}
class Book {
var pages: Vector[Page] = Vector()
def addPage(p: Page) { p.booked = Some(this); pages = pages :+ p }
}
// Create all your books and pages and assign them all
Page.everything.filter(_.booked.isEmpty) // This contains all unassigned pages
自分自身を追跡するために。(これはシングル スレッド コードを想定しています。専門知識のレベルでは、これを並列で実行する方法について心配する価値はおそらくありません。)
または、メソッドですべてが発生することを確認したい場合は、次のmain
ようにすることができます
// File Page.scala
class Page(text: String)(implicit mhm: MustHaveMe) {
}
// File Main.scala
object Main {
sealed trait MustHaveMe
private final object YesYouHaveMe extends MustHaveMe
def main(args: Array[String]) {
implicit val okayHere = YesYouHaveMe
new Page("Once upon a time")
}
}
現在、アクセス制限により、誰もがMain.scala
新しいページを作成することはできなくなり、ファイルmain
内のメソッドのみが. したがって、他の場所にオブジェクトを作成することを簡単に回避できます。Main.scala
Page
いいえ、自分で追跡する必要があります。どの言語も実際にこれを行うとは思わないでください。もちろん、これを行うようにクラスを作成することもできますが、それはあなたの責任です。
自分のページと本を個別に作成できる必要があります。私が興味を持っているのは、作成されたすべてのインスタンスを追跡することです。あなたが示唆したように、クラスブックも展開すると思います:
class Book(var name: String, var pages: List[Page]){
AllBook.allbook += this
}
object AllBook {
var allbook: Set[Book] = Set()
}
同様に、クラス Page も同様です。メイン メソッドの最後の命令として、制約を制御する必要があるメソッド呼び出し「検証」を使用します。
これでいいかも?より良い解決策はありますか?
注: 制約は、クラスの実装に関して独立しています。
下手な英訳ですみません