1. ホーム
  2. scala

Scalaの型記述の目的は何ですか?

2023-07-10 15:06:10

質問

タイプアスクリプションが何であるかについての情報はあまりなく、またその目的についても確かに何もありません。 varargs を渡すことができるようにする" 以外に、私は何のために type ascription を使うのでしょうか? 以下はその構文と効果に関するいくつかの scala REPL です。

scala> val s = "Dave"
s: java.lang.String = Dave

scala> val p = s:Object
p: java.lang.Object = Dave

scala> p.length
<console>:7: error: value length is not a member of java.lang.Object
       p.length
         ^
scala> p.getClass
res10: java.lang.Class[_ <: java.lang.Object] = class java.lang.String

scala> s.getClass
res11: java.lang.Class[_ <: java.lang.Object] = class java.lang.String

scala> p.asInstanceOf[String].length
res9: Int = 4

どのように解決するのですか?

型付けとは、ある式から期待される型を、有効な型の中からコンパイラに伝えることです。

型は分散や型宣言などの既存の制約を尊重し、適用される式が"の型のいずれかである場合に有効であると言えます。 "であるか、またはスコープ内で適用される変換がある場合です。

では java.lang.String extends java.lang.Object であるため、任意の String はまた Object . あなたの例では、式 s として扱われるように Object ではなく String . それを妨げる制約がなく、目的の型は s であれば、動作します。

さて、なぜそんなことをしたいのでしょうか?これを考えてみましょう。

scala> val s = "Dave"
s: java.lang.String = Dave

scala> val p = s: Object
p: java.lang.Object = Dave

scala> val ss = scala.collection.mutable.Set(s)
ss: scala.collection.mutable.Set[java.lang.String] = Set(Dave)

scala> val ps = scala.collection.mutable.Set(p)
ps: scala.collection.mutable.Set[java.lang.Object] = Set(Dave)

scala> ss += Nil
<console>:7: error: type mismatch;
 found   : scala.collection.immutable.Nil.type (with underlying type object Nil)
 required: java.lang.String
       ss += Nil
             ^

scala> ps += Nil
res3: ps.type = Set(List(), Dave)

また、タイプアスクリプティングで修正することもできます。 sss を宣言することもできますし、あるいは ss の型は Set[AnyRef] .

しかし、型宣言は識別子に値を代入している限りにおいてのみ、同じことを実現します。もちろん、一発勝負の識別子でコードを汚すことを気にしないのであれば、いつでもそうすることができます。例えば、次のようなものはコンパイルできません。

def prefixesOf(s: String) = s.foldLeft(Nil) { 
  case (head :: tail, char) => (head + char) :: head :: tail
  case (lst, char) => char.toString :: lst
}

しかし、これはそうです。

def prefixesOf(s: String) = s.foldLeft(Nil: List[String]) { 
  case (head :: tail, char) => (head + char) :: head :: tail
  case (lst, char) => char.toString :: lst
}

の代わりにここで識別子を使うのは馬鹿げています。 Nil . と書けばいいのですが List[String]() と書けばいいのですが、それはいつもできることではありません。例えば、こんなことを考えてみてください。

def firstVowel(s: String) = s.foldLeft(None: Option[Char]) { 
  case (None, char) => if ("aeiou" contains char.toLower) Some(char) else None
  case (vowel, _) => vowel
}

参考までに、Scala 2.7 spec (march 15, 2009 draft) の型付けに関する記述を紹介します。

Expr1 ::= ...
        | PostfixExpr Ascription

Ascription ::= ‘:’ InfixType
             | ‘:’ Annotation {Annotation}
             | ‘:’ ‘_’ ‘*’