1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Scala:コンストラクタに「上限境界」制約をかけて、条件を充足しないインスタンスの生成を禁じる

Last updated at Posted at 2021-11-07

###次のスクリプトファイルをコンパイルして実行する

####( クラス間の継承関係 )

HighLoyalityCustomerクラス --> NormalCustomerクラス --> Customerクラス --> Personクラス

####( 継承クラスのコンストラクタに付けた「上限境界」制約)

  • CustomerContainerクラスのコンストラクタは、Customerクラスそれ自体か、Customerクラスのサブクラスのみ受け入れる。
class CustomerContainer[C <: Customer](c: C) {

- GoodCustomerContainerクラスのコンストラクタは、HighLoyalityCustomerクラスそれ自体か、HighLoyalityCustomerクラスのサブクラスのみ受け入れる。

>```Scala:
>class GoodCustomerContainer[H <: HighLoyalityCustomer](h: H) {
>```


```Scala:bounded_class_test.scala 
object BoundedClassTest {
  def main(args: Array[String]){
     val customerContainer = new CustomerContainer[NormalCustomer](new NormalCustomer("Johnny", 15000))
     val goodCustomerContainer = new GoodCustomerContainer[HighLoyalityCustomer](new HighLoyalityCustomer("Ben", 7200000, 235))
     println(customerContainer.customer_name)
     println(goodCustomerContainer.customer_name)
     }

abstract class Person() {
 def get_name: String
}

class Customer(val cust_name: String) extends Person() {
  override def get_name: String = cust_name
}

class NormalCustomer(cust_name: String, val total_sales_price: Int) extends Customer(cust_name) {
  def get_sales_volume: Int = total_sales_price
}

class HighLoyalityCustomer(cust_name: String, total_sales_price: Int, val total_purchased_num: Int) extends NormalCustomer(cust_name: String, total_sales_price: Int) {
  def get_sales_count: Int = total_purchased_num
}


class CustomerContainer[C <: Customer](c: C) {
  def customer_name: String = c.get_name
}

class GoodCustomerContainer[H <: HighLoyalityCustomer](h: H) {
  def customer_name: String = h.get_name
}
}

###コンパイル実行(scalacコマンド)

  • 警告メッセージWarningは出ますが、コンパイルに成功しました。
  • スクリプトファイル内に記述したインスタンス生成のコードは、最初に見たすべての「上限境界」制約を満たしているので、コンパイルエラーを起こしませんでした。
Terminal
electron@diynoMacBook-Pro scala_test % scalac bounded_class_test.scala
warning: 1 deprecation (since 2.13.0); re-run with -deprecation for details
1 warning
electron@diynoMacBook-Pro scala_test %
  • 実行ファイル(BoundedClassTest .class)以下、各種ファイルが生成されている
Terminal
electron@diynoMacBook-Pro scala_test % ls | grep BoundedClassTest 
BoundedClassTest$.class
BoundedClassTest$Animal.class
BoundedClassTest$Cat.class
BoundedClassTest$Customer.class
BoundedClassTest$CustomerContainer.class
BoundedClassTest$Dog.class
BoundedClassTest$GoodCustomerContainer.class
BoundedClassTest$HighLoyalityCustomer.class
BoundedClassTest$Lion.class
BoundedClassTest$NormalCustomer.class
BoundedClassTest$Person.class
BoundedClassTest$Pet.class
BoundedClassTest$PetContainer.class
BoundedClassTest.class
electron@diynoMacBook-Pro scala_test % 

###scalaコマンドでクラスファイルを実行

Terminal
electron@diynoMacBook-Pro scala_test % scala BoundedClassTest
Johnny
Ben
electron@diynoMacBook-Pro scala_test % 

###REPLに読み込むスクリプトファイルを作成する

bounded_class_test2.scala
abstract class Person() {
 def get_name: String
}

class Customer(val cust_name: String) extends Person() {
  override def get_name: String = cust_name
}

class NormalCustomer(cust_name: String, val total_sales_price: Int) extends Customer(cust_name) {
  def get_sales_volume: Int = total_sales_price
}

class HighLoyalityCustomer(cust_name: String, total_sales_price: Int, val total_purchased_num: Int) extends NormalCustomer(cust_name: String, total_sales_price: Int) {
  def get_sales_count: Int = total_purchased_num
}


class CustomerContainer[C <: Customer](c: C) {
  def customer_name: String = c.get_name
}

class GoodCustomerContainer[H <: HighLoyalityCustomer](h: H) {
  def customer_name: String = h.get_name
}
}
  • REPLにロードして実行する。
  • REPL環境内で、最初に見たすべての「上限境界」制約を満たすインスタンス生成と、制約を満たさないインスタンス生成(の試み)を実行してみます。
Terminal
electron@diynoMacBook-Pro scala_test % scala
Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java 17.0.1).
Type in expressions for evaluation. Or try :help.

scala> :load bounded_class_test2.scala
val args: Array[String] = Array()
Loading bounded_class_test2.scala...
class Person
class Customer
class NormalCustomer
class HighLoyalityCustomer
class CustomerContainer
class GoodCustomerContainer

       }
       ^
bounded_class_test2.scala:1: error: eof expected but '}' found.

scala> 
  • customerContainerクラスのコンストラクタは、NormalCustomerクラスのインスタンス(new NormalCustomer("Johnny", 15000))を初期化変数として受け入れる。
Terminal
scala> val customerContainer = new CustomerContainer[NormalCustomer](new NormalCustomer("Johnny", 15000))
val customerContainer: CustomerContainer[NormalCustomer] = CustomerContainer@3cc2e3e

scala> println(customerContainer.customer_name)
Johnny

  • goodCustomerContainerクラスのコンストラクタは、HighLoyalityCustomerクラスのインスタンス(*new HighLoyalityCustomer("Ben", 7200000, 235))を初期化変数として受け入れる。
Terminal
scala> val goodCustomerContainer = new GoodCustomerContainer[HighLoyalityCustomer](new HighLoyalityCustomer("Ben", 7200000, 235))
val goodCustomerContainer: GoodCustomerContainer[HighLoyalityCustomer] = GoodCustomerContainer@7272914b

scala> println(goodCustomerContainer.customer_name)
Ben
  • goodCustomerContainerクラスのコンストラクタは、NormalCustomerクラスのインスタンス(new NormalCustomer("Johnny", 15000))を初期化変数として受け入れることができない。
  • goodCustomerContainerクラスは、上限境界であるHighLoyalityCustomerそれ自体か、HighLoyalityCustomerのサブクラスしか、初期化変数として受け入れない。
Terminal
scala> val goodCustomerContainer = new GoodCustomerContainer[NormalCustomer](new NormalCustomer("Johnny", 15000))
           ^
       error: type arguments [NormalCustomer] do not conform to class GoodCustomerContainer's type parameter bounds [H <: HighLoyalityCustomer]
                                       ^
       error: type arguments [NormalCustomer] do not conform to class GoodCustomerContainer's type parameter bounds [H <: HighLoyalityCustomer]
  • Personクラスは抽象クラスなので、インスタンスオブジェクトを生成できない(*new Person()*は実行不能)
  • 抽象クラスを継承したサブクラスからは、インスタンスを生成できる(そのサブクラスが抽象クラスでない場合)
Terminal
scala> val goodCustomerContainer = new GoodCustomerContainer[Person](new Person())
                                                                     ^
       error: class Person is abstract; cannot be instantiated

  • CustomerContainerクラスのコンストラクタは、HighLoyalityCustomerクラスのインスタンス(new HighLoyalityCustomer("Ben", 7200000, 235))を初期化変数として受け入れる。
  • CustomerContainerクラスのコンストラクタは、上限境界であるCustomerクラスそれ自体か、Customerクラスのサブクラスのインスタンスを受け入れることができる。
  • HighLoyalityCustomerクラスは、この「Customerクラスのサブクラス」という制約条件を満たしている。
Terminal
scala> val customerContainer = new CustomerContainer[HighLoyalityCustomer](new HighLoyalityCustomer("Ben", 7200000, 235))
val customerContainer: CustomerContainer[HighLoyalityCustomer] = CustomerContainer@23adbd6b

scala> println(customerContainer.customer_name)
Ben

scala>

ここで、以下が成立します。

  • HighLoyalityCustomerクラスは、NormalCustomerクラスのサブクラスである。
  • そのため、__もしも、CustomerContainerクラスの下限境界がNormalCustomerであったとしたら、「NormalCustomerのサブクラスである」 HighLoyalityCustomerクラスは受け入れられなかった。
  • HighLoyalityCustomerクラスは、「NormalCustomerクラスそれ自体か、NormalCustomerクラスのスーパークラスであること」という制約条件を満たさないため。

REPLを抜ける。

Terminal
scala> :q
electron@diynoMacBook-Pro scala_test % 

( 参考にしたウェブページ )

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?