私はScalaを初めて使用するので、type
キーワードについて多くを見つけることができませんでした。次の表現の意味を理解しようとしています。
type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
FunctorType
ある種のエイリアスですが、それは何を意味していますか?
私はScalaを初めて使用するので、type
キーワードについて多くを見つけることができませんでした。次の表現の意味を理解しようとしています。
type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
FunctorType
ある種のエイリアスですが、それは何を意味していますか?
回答:
はい、型のエイリアス FunctorType
は単なる省略形です
(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
タイプエイリアスは、コードの残りの部分を単純にするためによく使用されます。
def doSomeThing(f: FunctorType)
これはコンパイラによって次のように解釈されます
def doSomeThing(f: (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate)
これにより、たとえば、タプルや他のタイプで定義された関数などの多くのカスタムタイプを定義する必要がなくなります。
またtype
、たとえばScalaでのプログラミングのこの章で説明されているように、他にも興味深い使用例がいくつかあります。
実際、type
Scala のキーワードは、複雑な型を短い名前にエイリアスするだけではありません。タイプメンバーを紹介します。
ご存知のように、クラスはフィールドメンバーとメソッドメンバーを持つことができます。まあ、Scalaではクラスに型メンバーを含めることもできます。
あなたの特定のケースでtype
は、確かに、より簡潔なコードを書くことができるエイリアスを導入しています。型システムは、型チェックが実行されるときに、エイリアスを実際の型に置き換えるだけです。
しかし、あなたはこのようなものを持つこともできます
trait Base {
type T
def method: T
}
class Implementation extends Base {
type T = Int
def method: T = 42
}
クラスの他のメンバーと同様に、型メンバーも抽象(実際の値を指定しない)にすることができ、実装でオーバーライドすることができます。
ジェネリックで実装できるものの多くは抽象型メンバーに変換できるため、タイプメンバーはジェネリックのデュアルとして表示できます。
そうです、そうです、それらはエイリアシングに使用できますが、Scalaの型システムの強力な機能であるため、これだけに限定しないでください。
詳細については、この優れた回答をご覧ください。
Roland Ewaldの回答は、タイプエイリアスの非常に単純なユースケースで説明しており、詳細については非常に優れたチュートリアルを紹介していたので、気に入っています 。別のユースケースは、名前のこの記事で紹介しているので、タイプのメンバー、私はとても気に入って、それの最も実用的なユースケース、言及したいと思います。(この部分はから取られ、ここに :)
抽象型:
type T
上記のTは、使用されるこの型はまだ不明であり、具象サブクラスによっては定義されることを示しています。プログラミングの概念を常に理解するための最良の方法は、例を提供することです。次のシナリオがあるとします。
ここではコンパイルエラーが発生します。CowクラスとTigerクラスのeatメソッドは、Animalクラスのeatメソッドをオーバーライドしないためです。パラメータタイプが異なるためです。それは、牛のクラスのグラスであり、タイガーのクラスの肉対動物のクラスの食物であり、スーパークラスであり、すべてのサブクラスは適合しなければなりません。
ここで型の抽象化に戻ります。次の図と型の抽象化を追加するだけで、サブクラス自体に従って入力の型を定義できます。
次のコードを見てください。
val cow1: Cow = new Cow
val cow2: Cow = new Cow
cow1 eat new cow1.SuitableFood
cow2 eat new cow1.SuitableFood
val tiger: Tiger = new Tiger
cow1 eat new tiger.SuitableFood // Compiler error
コンパイラは満足しており、デザインを改善しています。牛に牛を与えることができます。SuitableFoodとコンパイラーは、タイガーに適した食品を牛に与えることを防ぎます。しかし、牛1適した食品と牛2吹田食品のタイプを区別したい場合はどうでしょう。言い換えると、型に(もちろんオブジェクトを介して)到達するパスが基本的に重要である場合、状況によっては非常に便利です。scalaの高度な機能により、次のことが可能になります。
パスに依存する型: Scalaオブジェクトは型をメンバーとして持つことができます。タイプの意味は、アクセスに使用するパスによって異なります。パスは、オブジェクト(クラスのインスタンス)への参照によって決定されます。このシナリオを実装するには、Cow内にGrassクラスを定義する必要があります。つまり、Cowは外部クラスで、Grassは内部クラスです。構造は次のようになります。
class Cow extends Animal {
class Grass extends Food
type SuitableFood = Grass
override def eat(food: this.SuitableFood): Unit = {}
}
class Tiger extends Animal {
class Meat extends Food
type SuitableFood = Meat
override def eat(food: this.SuitableFood): Unit = {}
}
このコードをコンパイルしようとすると、次のようになります。
1. val cow1: Cow = new Cow
2. val cow2: Cow = new Cow
3. cow1 eat new cow1.SuitableFood
4. cow2 eat new cow1.SuitableFood // compilation error
4行目では、GrassがCowの内部クラスであるためエラーが表示されます。したがって、Grassのインスタンスを作成するには、Cowオブジェクトが必要で、このCowオブジェクトがパスを決定します。したがって、2つの牛オブジェクトは2つの異なるパスを生成します。このシナリオでは、cow2は特別に作成された食品のみを食べたいと考えています。そう:
cow2 eat new cow2.SuitableFood
今、みんなが幸せです:-)
"type"をエイリアスとして使用する方法を示すための単なる例:
type Action = () => Unit
上記の定義では、Actionを、空のパラメーターリストを受け取り、Unitを返すプロシージャ(メソッド)のタイプのエイリアスとして定義しています。