Рассмотрим следующие базовые и производные классы в Scala:
abstract class Base( val x : String )
final class Derived( x : String ) extends Base( "Base's " + x )
{
override def toString = x
}
Здесь идентификатор 'x' параметра класса Derived переопределяет поле базового класса, поэтому вызов toString выглядит следующим образом:
println( new Derived( "string" ).toString )
возвращает производное значение и дает результат "строка".
Таким образом, ссылка на параметр 'x' побуждает компилятор автоматически генерировать поле в Derived, которое обслуживается при вызове toString. Обычно это очень удобно, но приводит к репликации поля (сейчас я храню поле как в Base, так и в Derived), что может быть нежелательно. Чтобы избежать этой репликации, я могу переименовать параметр класса Derived с «x» на что-то другое, например «_x»:
abstract class Base( val x : String )
final class Derived( _x : String ) extends Base( "Base's " + _x )
{
override def toString = x
}
Теперь вызов toString возвращает «строку Base», чего я и хочу. К сожалению, теперь код выглядит несколько уродливо, и использование именованных параметров для инициализации класса также становится менее элегантным:
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
Изменить 3. Было бы неплохо иметь способ подавить автоматическую генерацию поля, если бы в противном случае производный класс скрыл бы поле базового класса. Может показаться, что компилятор Scala на самом деле мог бы сделать это за вас, но, конечно, это противоречит более общему правилу «более близких» идентификаторов (класс Derived «x»), скрывающих более удаленные (класс Base). 'Икс'). Кажется, что достаточно хорошим решением был бы модификатор типа «новый», может быть, так:
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
val
, если значения двух полей могут различаться (т. Е. Если вы просто не передаете параметр конструктора базовому классу). Я не вижу способа ссылаться на Base.x из Derived (даже с использованием аннотации ссылки на себя). - person Aaron Novstrup   schedule 29.06.2011