ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Scalaコミュのscala質問

  • mixiチェック
  • このエントリーをはてなブックマークに追加
最近Liftの質問していますが、scala関係の質問は別トピックを立てようかと思います。
よく調査すればすぐに答えが見つかるかと思いますが他の初心者も助ける意味で質問します。
質問#1
Mapのメンバにスーパークラスとサブクラスをに持ったインスタンスを生成し、オブジェクトにアクセスするとoverrideしたメンバしかアクセスできない。多分、共変性とかいうキーワードに関係があるんだと思います。

クラスAとAをスーパークラスに持つBを定義します。
class A {
 def m = {
  printf("CLASS A")
 }
}

class B extends A {
 override def m = {
  printf("CLASS B")
 }
 def f = {
  printf("method f")
 }
}

それぞれインスタンス作って実行するとクラスA, クラスBの動作をします。
val a = new A
val b = new B
scala> a.m
CLASS A
scala> b.m
CLASS B
scala>

2つのインスタンスを持つMapを作成します。
val c = Map("a" -> a, "b" -> b)

マップのキーからそれぞれのオブジェクトを呼び出しメソッドを実行すると正しいクラスのメソッドが実行されます。
scala> c("a").m
CLASS A
scala> c("b").m
CLASS B

しかし、overrideしていないメソッドはmemberでないとおこられてしまいます。
scala> c("b").f
<console>:11: error: value f is not a member of A
    c("b").f
        ^
これはなぜでしょう。また、overrideしていないサブクラスだけのメソッドを実行する方法はありますでしょうか?

よろしくお願いします。

コメント(9)

僕も始めたばかりで詳しくないのですが...

val c は,Map<A> なので,c("b") で取り出したデータも A クラスとなります.A クラスには f メソッドが定義されていないので,呼び出そうとするとエラーになります.

コンソールで実行した以下からも明らかです.
scala> c("b")
res10: A = B@3b3757

そこで,asInstanceOf[クラス名] でキャストしたり,isInstanceOf[クラス名] でキャストできるかの判定ができます.
scala> if ( c("b").isInstanceOf[B] ) { c("b").asInstanceOf[B].f }
method f

しかし,これはでは scala っぽくないので,match をよく使うと思います.
scala> c("b") match { case b : B => b.f }
method f


あと c("b") で取得するより,c.get("b") で取得したほうが安全なのでは?と思うのですが,どうなんでしょう?
scala> c.get("b") match { case Some(b: B) => b.f; case _ => () }
method f
書き込みありがとうございます。なるほど型マッチを行ってメソッドを実行させるのですね。
おかげさまでやっと思い通りの動きができるようになりました。
いまは動きを確認する意味でgetなど使っていないのですがそのうち見直して実装し用と思います。

今は複数のデータを保持できるBeanを作っていて同じスーパークラスを持つデータ群に同じメソッドを実行させたかったのです。状況によって変わる複数のデータにアクセスするのにscalaでは何が有効か考えた結果Mapを思いついたのですがこれが正しい考え方なのかわからないでいます。

説明できるようになったら書き込もうと思います。
もしかしたらここに投稿するよりもandroidのコミュが正しいかもしれませんが。

androidでscalaを使ってアプリケーション作ってみました。
eclipse上ではコンパイルできるのですがAVD上で実行すると
NoClassDefFoundError: scala.collection.immutable.List$といったエラーができます。
scalaのライブラリがAVD上にインストールされていないようで、外部ライブラリを使うための設定として
AndroidManifest.xmlに

<uses-library android:name="scala.library" android:required="true" />
<uses-library android:name="scala.collection" android:required="true" />
<uses-library android:name="scala.collection.immutable" android:required="true" />

といった記述を付け加えました。
しかし、現在はAVDへのインストール時に

Installation error: INSTALL_FAILED_MISSING_SHARED_LIBRARY

といったメッセージが出てインストールに失敗します。
インストールするパッケージ、jarファイルなどどこに配置したらよいのでしょうか。
ご存知の方おりましたら教えてください。
>>[4]
238〜239ページを参照してください。
Scala IOが必要になります。
sbtを使っていない場合は、クラスパスにscala-io-coreのjarを追加する形になるでしょうか。

エディタだと大変だと思うので、intellij ideaを使ってみるのもおすすめします。
個人的にはeclipseよりこちらのほうがScalaに強いと思います。
>>[7]
githubからDLできるのは基本的にソースのみです。
なので、ビルドしてjarを作る必要があります。
Scalaの場合、ビルドにはsbtというツールを使うことが多いです。
https://github.com/jesseeichar/scala-io からDLできるものもsbtでのビルドが前提になっています。

が、そもそも自分が書いたソースをsbtを使ってビルドすれば
sbtの設定ファイルに書いたライブラリをビルド時に勝手にDLしてくるので
Scala IOのjarを作成したりDLしてくる必要はなかったりします。
sbtの使い方は逆引きレシピにも載っていますので、そちらを参照してみてください。

どうしてもお手軽に試したい場合は、
http://jesseeichar.github.com/scala-io-doc/0.4.2/#!/getting-started から
jarがDLできるようなので、そちらから入手してみてください。

ただ、Scala IOも内部的には結局java.ioを叩いているようなので
java.ioを使うことをそんなに忌避しなくても良いのではないかと思います。
結局コンパイル後はJavaと同様の成果物ができあがるので・・・。

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Scala 更新情報

Scalaのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング