Идиоматический способ Scala работать с именами полей базового и производного классов?

Рассмотрим следующие базовые и производные классы в Scala:

    abstract class Base( val x : String )

    final class Derived( x : String ) extends Base( "Base's " + x )
    {
        override def toString = x
    }

Здесь идентификатор 'x' параметра производного класса переопределяет поле базовый класс, поэтому вызов toString выглядит следующим образом:

    println( new Derived( "string" ).toString )

возвращает значение Derived и дает результат "string".

Таким образом, ссылка на параметр 'x' побуждает компилятор автоматически сгенерировать поле в Derived, которое является обслуживается при вызове toString. Обычно это очень удобно, но приводит к репликации поля (сейчас я сохраняю поле как на Базовом, так и на Производном), что может быть нежелательно. Чтобы избежать этой репликации, я могу переименовать параметр класса Derived с 'x' на что-нибудь другое, например '_x':

    abstract class Base( val x : String )

    final class Derived( _x : String ) extends Base( "Base's " + _x )
    {
        override def toString = x
    }

Теперь вызов toString возвращает «Базовую строку», что я и хочу. К сожалению, код теперь выглядит несколько некрасиво, и использование именованных параметров для инициализации класса также становится менее элегантным:

    new Derived( _x = "string" ) 

Также существует риск забыть дать параметрам инициализации производных классов разные имена и непреднамеренно обратиться к неправильному полю ( нежелательно, поскольку базовый класс может фактически содержать другое значение.)

Есть ли лучший способ?

Редактировать 1 : Чтобы уточнить, мне действительно нужны только базовые значения; Производные просто кажутся необходимыми для инициализации полей базового класса. Пример ссылается на них только для иллюстрации возникающих проблем.

Редактировать 2 : На самом деле, пример был бы более ясным, если бы я использовал vars вместо vals, поскольку это подчеркивает проблему с изменением значений позже в базовом классе:

    class Base( var x : Int ) { def increment() { x = x + 1 } }
    class Derived( x : Int ) extends Base( x ) { override def toString = x.toString }

    val derived = new Derived( 1 )
    println( derived.toString )     // yields '1', as expected
    derived.increment()
    println( derived.toString )     // still '1', probably unexpected

Edit 3 : Было бы неплохо иметь способ подавить автоматическую генерацию поля, если бы производный класс иначе в конечном итоге скрывал бы поле базового класса. Казалось бы, компилятор Scala действительно мог быть разработан для этого за вас, но, конечно, это противоречит более общему правилу «более близких» идентификаторов (производный класс «x»), скрывающих более удаленные (базовый класс » 'Икс'). Похоже, что достаточно хорошим решением был бы модификатор типа 'noval', может быть примерно так:

    class Base( var x : Int ) { def increment() { x = x + 1 } }
    class Derived( noval x : Int ) extends Base( x ) { override def toString = x.toString }

    val derived = new Derived( 1 )
    println( derived.toString )     // yields '1', as expected
    derived.increment()
    println( derived.toString )     // still '2', as expected
9
задан Gregor Scheidt 29 June 2011 в 08:17
поделиться