抽象型を使い始めたばかりです。完全に理解できないエラーが発生しています。背景のコードの一部を次に示します。
abstract class DbfReader( fileName: String )
{
type DBFDataType <:Any
type Key <:Any
type Value <:Any
abstract class FieldMapping
{
type FieldType
def acronym: Key
def longName: Key
def fieldNum: Int
def getField: FieldType
def getFieldLength: Int
}
def fieldMappings: Map[ Key, FieldMapping ]
def getFieldCount: Int
def hasRecord(): Boolean
def getRecord(): DBFDataType
def getFieldVal( fieldName: Key )( rowData: DBFDataType ): Value
protected def createFieldMapping( fieldAcro: Key,
fieldLongName: Key,
fieldPosition: Int ): FieldMapping
....
}
抽象クラス DbfReader は、私が試しているライブラリを読み取るさまざまな DBF (データベース ファイル) への抽象ラッパーであることを意図しています。抽象クラスには、FieldMapping の内部クラスがあります (テーブル メタ データFieldType
は、データベース フィールドの基礎となるライブラリ表現のプレースホルダーとなることを意図した抽象型を持つテーブル メタ データです。getField
内部クラスのルーチンは、この型の参照を返します。
以下は、この抽象クラスの具体的な実装です。
class MyDBFReader( fileName: String, fmap: List[( String, String, Int )] ) extends DbfReader( fileName )
{
type DBFDataType = Array[Object]
type Key = String
type Value = String
val dbReader = new jdbf.DBFReader( new java.io.FileInputStream( theFile ) )
val fieldMappings = addFieldMappings(fmap)(Map())
case class InnerFieldMapping( acronym: Key, longName: Key, fieldNum: Int) extends FieldMapping
{
type FieldType = jdbf.JDBField
override def getField: jdbf.JDBField = dbReader.getField( fieldNum )
def getFieldLength = getField.getLength
}
def getFieldCount = dbReader.getFieldCount
def hasRecord = dbReader.hasNextRecord
def getRecord = dbReader.nextRecord
def createFieldMapping( fieldAcro: String, fieldLongName: String, fieldPosition: Int ) = InnerFieldMapping( fieldAcro, fieldLongName, fieldPosition )
def getFieldVal( fieldName: Key )( rowData: DBFDataType ) = {
if( fieldMappings.keySet.contains( fieldName ) ) stringer( rowData( fieldMappings( fieldName ).fieldNum - 1 ) )
else
throw new NoSuchElementException( "Key " + fieldName + " not Found" )
}
private def stringer( r: Object ) = r.asInstanceOf[String].trim
}
私が遭遇している問題は、抽象的な Field マッピングを拡張する InnerFieldMapping から getField を呼び出そうとしたときです。次のような単体テストでこれを試しています:
問題が発生する場所
class MyDBFSuite extends FunSuite {
val fileName = "/Users/Me/api11bdb.dbf"
val dbf = new MyDBFReader( fileName, DbfReader.SchoolFieldMapping )
test( "Dbf should have 150 fields" )
{
assert( dbf.getFieldCount === 150 )
}
test( "Should read a record" )
{
assert( dbf.hasRecord === true )
assert( dbf.getRecord.size === 150 )
}
test( "Should Get a Field" )
{
println( dbf.fieldMappings.head._2.getField.getType )
//assert( dbf.fieldMappings.head._2.getField.getType === "S" )
}
DBFField
最後のテスト (アサートを有効にするか、または println で) では、内部クラスInnerFieldMapping
ルーチン getFieldから期待されるルーチンである getType にアクセスしようとするたびに。抽象グラスでは、ルーチンは の戻り値の型を指定しますFieldType
。これは具象クラスで jdbf.JDBFField として実装します。
ただし、コンパイラは次のように述べています 。
src/test/scala/ChinaDBFTestSuite.scala:23: value getType is not a member of MyDBFSuite.this.dbf.FieldMapping#FieldType
[error] println( dbf.fieldMappings.head._2.getField.getType )
[error] ^
もう 1 つのテストでは、抽象クラスで抽象型を返す外部クラス ルーチン getRecord を呼び出します。コンパイラには問題はありませんでした。エラー メッセージを見ると、FieldType が内部の抽象クラス定義に準拠していると思われます。つまり、MyDBFSuite.this.dbg.InnerFieldMapping.FieldType を探すようにします。ここで本質的に間違ったことをしていますか?
編集:答えてくれてありがとう。フォローアップとして、オーバーライドについても質問がありますか? scala book では、抽象型を返すメソッドがサブタイプでオーバーライドされていることに気付きましたが、ここではこれを行わず、サブタイプをインスタンス化するときにコンパイラが実装の欠落について文句を言いません。メソッドの戻り値の型が (基本クラスで定義されているように) 抽象型である場合、サブクラス メソッドでオーバーライド タグが必要なのはなぜですか?