Подтвердить что ты не робот

Почему классы, которые не расширяют другие классы, должны простираться от черт? (с не работает)

Я начинаю с Scala, и я нашел это немного странным. В 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!

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

Спасибо!

4b9b3361

Ответ 1

Прежде всего обратите внимание, что расширение/реализует разницу ничего не сообщает компилятору, чем он не знал. Я не имею в виду, что это плохо, только то, что язык мог бы сделать иначе. В С# вы пишете class A : B, C, D вместо class A extends B implements C, D и class A implements B, C, D. Поэтому вы можете просто подумать, что Scala extends подобен двоеточию и 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.

Ответ 2

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

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

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

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

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

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

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

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

(Здесь Philosophical является признаком.)

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

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