Почему классы, которые не расширяют другие классы, должны простираться от черт? (с не работает)
Я начинаю с 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!
Итак, что мне не хватает? Не имеет смысла использовать черту, не расширяя ее?
Спасибо!
Ответы
Ответ 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
не является верхним типом, но он довольно близок.)