2010-07-26 2 views
1

Пара вопросов о Scala абстрактных типов.Scala абстрактные пути зависимых типа проблема часть 2

  1. Должен ли я использовать параметризованные типы [], если я хочу использовать тип в значении конструктора? то есть. возможно ли иметь класс с абстрактными типами параметров конструктора? Если я избавлюсь от [T1, T2] и использую INode # TKey и INode # TValue как типы параметров конструктора, что я делаю? Я получаю путаные сообщения об ошибках.
  2. Как я могу решить эту проблему, не прибегая к внутренним типам? Мое использование INode в определениях, по-видимому, подразумевает, что я мог бы вернуть/получить INode с различными типами для TKey & TValue. Как ограничить его теми же типами TKey/TValue, что и мой текущий тип, не ограничивая себя возвратом/получением именно этого «экземпляра»?
trait AbsTypes 
{ 
    type TKey 
    type TValue 
} 
trait INode extends AbsTypes 
{ 
    def get(key : TKey) : TValue 
    def set(key : TKey, v : TValue) : INode 
    def combine(other : INode, key : TKey): INode 
} 
class ANode[T1,T2](
    val akey : T1, 
    val aval : T2 
) extends INode 
{ 
    type TKey = T1 
    type TValue = T2 
    type Node = ANode[T1,T2] 
    def get(key : TKey) : TValue = { aval } 
    def set(key : TKey, v : TValue) : INode = { 
    new ANode(key,v) 
    } 
    def combine(other : INode, key :TKey) : INode = { 
    //ERROR : type mismatch; found : key.type (with underlying type ANode.this.TKey) required: other.TKey 
    other.set(key, aval) 
    } 
} 
+1

См http://stackoverflow.com/questions/1154571/scala-abstract-types-vs-generics для обсуждения, когда использовать абстрактные типы в сравнении параметризованных типов – oluies

ответ

2

Я думаю, параметризованные типы идеально вписываться в вашей обстановке. Абстрактные типы привязаны к определенному экземпляру, следовательно, ошибка, которую вы получаете. Я признаюсь, что не пытался реорганизовать ваш пример, чтобы сделать абстрактные типы, но следующий фрагмент не пытается смешивать абстрактные и параметризованные типы, и у scalac нет никаких проблем с ним.

trait INode[TKey, TValue] 
{ 
    type Node = INode[TKey, TValue] 

    def get(key : TKey) : TValue 
    def set(key : TKey, v : TValue) : Node 
    def combine(other : Node, key : TKey): Node 
} 
class ANode[TKey,TValue](
    val akey : TKey, 
    val aval : TValue 
) extends INode[TKey, TValue] 
{ 
    def get(key : TKey) : TValue = aval 
    def set(key : TKey, v : TValue) : Node = new ANode(key,v) 
    def combine(other : Node, key : TKey) : Node = other.set(key, aval) 
} 
+1

приведено в руководстве Scala стиля для стиля параметра типа руководство http://davetron5000.github.com/scala-style/naming_conventions/type_parameters/index.html – oluies

2

Прежде всего я хотел бы отметить, что метод combine не использует параметр other на всех, вы могли бы точно так же написать:

def combine(key : TKey) : Node = set(key, aval) 

.. но я думаю, это просто принцип, который мы здесь делаем.

Если у вас есть очень небольшой набор допустимых комбинаций TKEY и TValue (скажем, 2), вы можете использовать тактику абстрактных типов и вырезать параметризованные типы из кода все вместе:

trait INode 
{ 
    type TKey 
    type TValue 
    def get(key : TKey) : TValue 
    def set(key : TKey, v : TValue) : INode 
    def combine(other : INode, key : TKey): INode 
} 

case class StringNode(
    val m_key : String, 
    val m_val : String 
) extends INode 
{ 
    type TKey = String 
    type TValue = String 
    override def get(key : TKey) : TValue = { m_val } 
    override def set(key : TKey, v : TValue) : INode = new StringNode(key,v) 
    override def combine(other : INode, key :TValue): INode = { 
    other match { 
     case node: StringNode => node.set(key, m_val) 
     case _ => throw new IllegalArgumentException("Not OK bla bla") 
    } 
    } 
} 

В моем примере вы получите некоторое дублирование кода в методах StringNode и, скажем, IntNode, но проиллюстрирован, по крайней мере, принцип абстрактных типов.

2

С other другой INode, он имеет собственные TKey и TValue. Нет гарантии, что TKey и TValue этого ANode соответствуют номерам other. Вам нужно ограничить типы с помощью равенства или нижней границы (что я использовал). Я не пытался бежать, но следующий компилирует против Scala 2.8.0

trait AbsTypes { 
    type TKey 
    type TValue 
    } 
    trait INode extends AbsTypes { 
    def get(key : TKey) : TValue 
    def set(key : TKey, v : TValue) : INode 
    //def combine(other : INode, key : TKey): INode 
    type TNode = INode { 
        type TKey >: INode.this.TKey 
        type TValue >: INode.this.TValue 
       } 
    def combine(other : TNode, key : TKey) : INode 
    } 
    class ANode[T1,T2](val akey : T1, val aval : T2) extends INode { 
    type TKey = T1 
    type TValue = T2 
    type Node = ANode[T1,T2] 
    def get(key : TKey) : TValue = { aval } 
    def set(key : TKey, v : TValue) : INode = { 
     new ANode(key,v) 
    } 
    def combine(other : TNode, key : TKey) : INode = { 
     other.set(key, aval) 
    } 
    } 
0

Спасибо за ваши ответы, они наиболее полезны & действительно помогли моему пониманию. Одно из альтернативных решений, которые я нашел ниже. AbsType не обязательно должен быть базовым классом, вы можете использовать его для завершения определения параметризованного типа.


class ANode[T <: AbsTypes](
    val akey : T#TKey, 
    val aval : T#TValue 
) extends INode[T] 
{ 
    def get(key : TKey) : TValue = { aval } 
    def set(key : TKey, v : TValue) : Node = { 
     new ANode[T](key,v) 
    } 
    def combine(other : Node, key : TKey) : Node = { 
     other.set(key, aval) // "use" this & other somehow 
    } 
} 

// Examples 
class AbsTypeDef[TKey1, TValue1] extends AbsTypes 
{ 
    type TKey = TKey1 
    type TValue = TValue1 
} 

object ANode 
{ 
    type AIntString = AbsTypeDef[Int,String] 
    type AStringLong = AbsTypes { type TKey = String; type TValue = Long} 
    def n1 = new ANode[AIntString](1,"one") 
    def n1b = new ANode[AIntString](2,"two") 
    def n2 = new ANode[AStringLong]("two",2L) 
    n1.combine(n1b,2) 
    //n1.combine(n2,2) // compile error 
}

 Смежные вопросы

  • Нет связанных вопросов^_^