Scalaの抽象メンバー
3928 ワード
Key Words:
抽象メンバー(Abstract Members)
クラスまたは特質のメンバーが抽象的であるかどうかは、主にそのメンバーがクラスまたは特質で宣言され、サブクラスによって実現される完全な定義抽象メンバーがあるかどうかにかかっている.
抽象メソッド、Scalaに加えて、クラスまたは特質のメンバーとして抽象フィールド、さらには抽象タイプ(types)を宣言することもできます.
Scalaでは、以下に示すように、4つのメンバーの抽象、
Scalaでは抽象クラスも特質も抽象タイプとは呼ばれない.抽象タイプは常に抽象クラスまたは特質のメンバーとして存在し、抽象メンバーは特定のクラス(Concrete)において
抽象型の2つの用途:1.冗長なクラス名の簡略化方法2を提供する.宣言された抽象タイプは、サブクラスで定義される必要があります.
抽象不変値(vals)
抽象不変値(abstract val)は、その論理的実装を制約します.不変値(val)のみで定義でき、varまたはdefで定義できません.
抽象メソッド(パラメータなし)はdefまたはvalで定義できます
抽象不変値の初期化
不変値初期化の理解では、クラスパラメータとしてクラス初期化前に評価されることを覚えておく必要があります.特質の抽象不変値として,通常の匿名クラスの初期化方式では,特質の初期化後に評価され,関連する問題を引き起こす可能性がある.対応策は
特質における抽象不変値の初期化順序がもたらす可能性のある問題に鑑み、
抽象可変値(vars)
抽象可変値には特別なところがある.クラスにvarメンバーを定義すると、コンパイラは自動的にそのメンバーにgetterメソッドとsetterメソッドを追加します.抽象的なvarを宣言すると、コンパイラはメンバーにgetterとsetterを暗黙的に追加しますが、次のように値を割り当てるフィールドは定義されません.
抽象可変値は、サブクラスでvarまたはdefを使用して定義できますが、注意すべき点があります.
上記のコード例では、コンパイルは可能であるが、
抽象型(Abstract Type)
抽象型の宣言は、サブクラスで具体化する必要があるプレースホルダです.つまり、具体的な定義は継承システムの最下位に落ちます.
通常、抽象タイプの使用は、上界の制約に合わせて行われます.以下に示します.
パス依存型(Path-dependent types)
パス依存型の「パス」は、
名前から理解できるように、このタイプはパスに依存し、異なるパスは異なるタイプを与える.
Java内部クラスとの違い
1.パス依存型ネーミング(names)外部オブジェクト、内部クラスネーミング外部クラス名2.Scalaでは
その他
1.パス依存型のインスタンスは外部オブジェクトの参照を持つ.
改良タイプ(Refinement Type)
改良タイプとは、サブタイプ間に互換性のあるメンバー(compatible members)が含まれているため、構造化されたサブタイプ(structural subtyping)であり、簡単なサブタイプ関係を得ることができる.
構造サブタイプに対応する名前付きサブタイプ(Nominal subtyping)は、通常、より便利で、短い識別子を持つため、構造サブタイプに表示されるリスト・メンバー・タイプとは異なり、より簡単です.
しかし、構造サブタイプは通常より柔軟で、多くの面白いことを抽象化することができます.
列挙
Scalaにおける経路依存型の応用例を列挙する
Color.ValueはRed,Green,Blueのパス依存型である.
abstract member
, pre-initialized fields
, lazy vals
, path-dependent types
, enumerations
抽象メンバー(Abstract Members)
クラスまたは特質のメンバーが抽象的であるかどうかは、主にそのメンバーがクラスまたは特質で宣言され、サブクラスによって実現される完全な定義抽象メンバーがあるかどうかにかかっている.
抽象メソッド、Scalaに加えて、クラスまたは特質のメンバーとして抽象フィールド、さらには抽象タイプ(types)を宣言することもできます.
Scalaでは、以下に示すように、4つのメンバーの抽象、
vals
、vars
、methods
、types
があります.trait Abstract {
type T
def transform(x: T): T
val initial: T
var current: T
}
type
キーワードを使用して抽象タイプを宣言します.このタイプには正確な定義が指定されていません.Scalaでは抽象クラスも特質も抽象タイプとは呼ばれない.抽象タイプは常に抽象クラスまたは特質のメンバーとして存在し、抽象メンバーは特定のクラス(Concrete)において
の形式として存在する.抽象型の2つの用途:1.冗長なクラス名の簡略化方法2を提供する.宣言された抽象タイプは、サブクラスで定義される必要があります.
抽象不変値(vals)
抽象不変値(abstract val)は、その論理的実装を制約します.不変値(val)のみで定義でき、varまたはdefで定義できません.
抽象メソッド(パラメータなし)はdefまたはvalで定義できます
抽象不変値の初期化
不変値初期化の理解では、クラスパラメータとしてクラス初期化前に評価されることを覚えておく必要があります.特質の抽象不変値として,通常の匿名クラスの初期化方式では,特質の初期化後に評価され,関連する問題を引き起こす可能性がある.対応策は
(pre-initialized fields)
と (lazy vals)
の2つですtrait RationalTrait {
val numerArg: Int
val denomArg: Int
}
class Rational(numer: Int, denom: Int)
// RationalTrait expr1,expr2
new RationalTrait {
val numerArg = expr1
val denomArg = expr2
}
// Ratinal expr1,expr2
new Rational(expr1, expr2)
特質における抽象不変値の初期化順序がもたらす可能性のある問題に鑑み、
を用いて初期化順序を正確に制御するか、
を用いて遅延処理フィールドの初期化を行う//
new {
val numerArg = expr1
val denomArg = expr2
} with RationalTrait
//
trait RatinalTrait {
lazy val numerArg: Int
lazy val denomArg: Int
}
new RationalTrait {
val numerArg = expr1
val denomArg = expr2
}
抽象可変値(vars)
抽象可変値には特別なところがある.クラスにvarメンバーを定義すると、コンパイラは自動的にそのメンバーにgetterメソッドとsetterメソッドを追加します.抽象的なvarを宣言すると、コンパイラはメンバーにgetterとsetterを暗黙的に追加しますが、次のように値を割り当てるフィールドは定義されません.
trait Foo {
var bar: String
}
//
trait Foo {
def bar: String
def bar_=(x: String)
}
抽象可変値は、サブクラスでvarまたはdefを使用して定義できますが、注意すべき点があります.
trait Foo {
var bar: String
}
// var
class ConcreteFoo extends Foo {
override var bar: String = "hello"
}
// def
class ConcreteFoo extends Foo {
override def bar: String = "hello"
override def bar_=(x: String) = x
}
上記のコード例では、コンパイルは可能であるが、
bar_=
メソッドは、xの値をベアラするために付与可能なフィールドがないため、実際の意味を持たない.抽象型(Abstract Type)
抽象型の宣言は、サブクラスで具体化する必要があるプレースホルダです.つまり、具体的な定義は継承システムの最下位に落ちます.
通常、抽象タイプの使用は、上界の制約に合わせて行われます.以下に示します.
class Food
abstract class Animal {
type SuitableFood <: food="" def="" eat="" suitablefood=""/>
パス依存型(Path-dependent types)
パス依存型の「パス」は、
farm.barn.bessy
、farm、barn、bessyなどのオブジェクトの変数名を指します.名前から理解できるように、このタイプはパスに依存し、異なるパスは異なるタイプを与える.
Java内部クラスとの違い
1.パス依存型ネーミング(names)外部オブジェクト、内部クラスネーミング外部クラス名2.Scalaでは
Outer#Inner
で表され、JavaではOuter.Inner
で表されるその他
1.パス依存型のインスタンスは外部オブジェクトの参照を持つ.
new Outer#Inner
を直接使用してパス依存タイプを初期化することはできません.改良タイプ(Refinement Type)
改良タイプとは、サブタイプ間に互換性のあるメンバー(compatible members)が含まれているため、構造化されたサブタイプ(structural subtyping)であり、簡単なサブタイプ関係を得ることができる.
構造サブタイプに対応する名前付きサブタイプ(Nominal subtyping)は、通常、より便利で、短い識別子を持つため、構造サブタイプに表示されるリスト・メンバー・タイプとは異なり、より簡単です.
しかし、構造サブタイプは通常より柔軟で、多くの面白いことを抽象化することができます.
// animal that eats grass
Animal { type SuitableFood = Grass }
class Pastrue {
var animals: List[Animal { type SuitableFood = Grass}] = Nil
}
列挙
Scalaにおける経路依存型の応用例を列挙する
object Color extends Enumeration {
val Red, Green, Blue = Value
}
Color.ValueはRed,Green,Blueのパス依存型である.