Почему классы, которые не расширяют другие классы, должны расширяться от черт? (с не работает) - PullRequest
12 голосов
/ 10 ноября 2011

Я начинаю со Скалы, и мне это показалось немного странным.В Java я мог бы сделать что-то вроде этого:

interface Foo{}

public class Bar implements Foo{}

Я пытаюсь сделать что-то подобное со Scala, но это не работает:

trait Foo;
class Bar with Foo; // This doesn't work!

Я должен использоватьКлючевое слово "extends":

class Bar extends Foo; // This works OK!

Теперь все в порядке, но это не то, что я хотел.

Еще одна странная вещь, которую я заметил, заключается в том, что каждый класс в Scala выходит из AnyRef (см. этоизображение из scala-lang.org: http://www.scala -lang.org / sites / default / files / images / classhierarchy.png ) я могу сделать это:

class Bar extends AnyRef with Foo; // This works too!

Итак,что мне не хватает?Нет смысла использовать черту, не расширяя ее?

Спасибо!

Ответы [ 3 ]

21 голосов
/ 10 ноября 2011

Во-первых, обратите внимание, что разница в расширении / реализации ничего не говорит компилятору, чем он не знал бы. Я не имею в виду, что это плохо, просто язык мог поступить иначе. В C # вы пишете class A : B, C, D вместо обоих class A extends B implements C, D и class A implements B, C, D. Так что вы можете просто думать, что extends в Scala - это двоеточие, а with - как запятая.

Тем не менее, в старые времена это было class Bar with Foo. Он изменился, когда Scala вышла 2.0 в 2006 году. См. история изменений .

Кажется, я помню (не уверен), что причина была просто в том, что class Bar with Foo плохо читает.

В Scala A with B - это пересечение типов A и B. Объект имеет тип A with B, если он имеет тип A и тип B. Так что class A extends B with C может быть прочитано class A расширяет тип B with C. Нет такой вещи с class A with B.

8 голосов
/ 10 ноября 2011

Если вы пришли с Java, поначалу это может звучать странно (это было то же самое для меня), но на самом деле сейчас я нахожу более регулярный синтаксис, чем у Java, где мне нужно явно сказать, хочу ли я implement или extend другой класс / интерфейс. Но я думаю, что это больше вопрос личного вкуса.

На самом деле не имеет значения, говорите ли вы extends или implements. Они оба представляют один и тот же тип отношений между двумя вещами: представляет собой (в отличие от делегирования и композиции, которые представляют , имеет отношение ). Вот, например, вы можете найти дополнительную информацию об этом:

http://www.javacamp.org/moreclasses/oop/oop5.html

Просто попробуйте заменить extends, implements, with на is a, и это станет более понятным.

В Scala у вас также есть другие варианты отношения is a. Например self types :

trait Bar {
   self: Foo =>
   // ...
}

При этом вы говорите, что Bar не расширяет / не реализует Foo напрямую, но все другие классы, которые хотят расширить Bar, также должны расширять Foo.

Самостоятельные типы могут позволять интересные вещи. Например, два класса / черты, которые зависят друг от друга:

class Bar extends Foo {
    def sayHello(name: String) = println("Hello, " + name)

    greet()
}

trait Foo {
    this: Bar =>

    def greet() = sayHello("User")
}

new Bar() // prints: Hello, User
3 голосов
/ 10 ноября 2011

Программирование в Scala (2-е изд) обсуждает черты в главе 12. Он отмечает, что касается extends:

Вы можете использовать ключевое слово extends, чтобы смешивать черты характера; в этом случае вы неявно наследуют суперкласс черты. Например, в листинге 12.2 класс Frog подклассы AnyRef (суперкласс Philosophical) и миксы в Philosophical.

(Здесь Philosophical - это черта.)

Итак, ваши рассуждения абсолютно верны.

По теме AnyRef вы должны прочитать о иерархии классов Scala и верхних типах . (AnyRef не самый верхний тип, но он довольно близок.)

...