#java #groovy
#java #groovy
Вопрос:
Как мне определить список из двух объектов (Foo, Bar) и выполнить итерацию по нему?
Что я пробовал:
// create
def fooBar = new ArrayList<Foo, Bar>()
fooBar.add(new Foo())
fooBar.add(new Bar())
fooBar.add(new Foo()) // << shouldn't be allowed or overwrite first foo
def fooBars = new ArrayList<List<Foo, Bar>>()
fooBars << fooBar
// read
fooBars.each { fooBar ->
def foo = fooBar[0]
def bar = fooBar[1]
// do something with foo and bar
}
Чего я хочу:
// pseudo code
def fooBar = new ???<Foo, Bar>()
fooBar.set(new Foo())
fooBar.set(new Bar())
def fooBars = new ArrayList<???>()
fooBars << fooBar
fooBars.each { fooBar ->
def foo = fooBar[???] // 0, 'foo', ..?
def bar = fooBar[???]
// do something with foo and bar
}
Если создание моего собственного класса FooBar является решением, я в порядке, я просто надеюсь, что есть более простое решение.
Комментарии:
1. Вы могли бы попробовать
new AbstractMap.SimpleEntry<Foo, Bar>(...)
2. Неясно, что именно вы пытаетесь сделать. Вы пытаетесь создать список, в котором каждый элемент списка является либо Foo, либо Bar? Если это так, то вы хотите
ArrayList<Object>
. Похоже, вы также можете пытаться создать список пар Foo и Bars, и в этом случае вам нужно будет либо использовать какой-тоPair<T1, T2>
класс, указанный где-то в какой-то библиотеке, либо написать свой собственный, а затем составить из этого список.3. @user3030010 Как я понял, OP хочет список ровно из 2 элементов: один Foo и один Bar. Другими словами, кортеж / пара.
4. @Klitos Kyriacou: Да @user3030010: Я привел плохой пример, вместо
Foo
иBar
рассмотрим экземплярFile
иFileReader
, который имеет смысл только в комбинации / как пара.
Ответ №1:
В Groovy есть понятие кортежей.
def tuple = new Tuple('one', 1)
def (String a, Integer b) = tuple
println a
println b
или альтернативно
def doSomething(String s, Integer i) {
println s
println i
}
doSomething(tuple)
или альтернативно
def doSomething(Tuple t) {
println t[0]
println t[1]
}
doSomething(tuple)
затем вы можете сделать
def tuples = [ ] << tuple << tuple
tuples.each { doSomething(it) }
Комментарии:
1. И если вам нужны обобщения, есть
Tuple2
, т.Е.:new Tuple2<Foo, Bar>(foo, bar)
2. Как выглядит этот список объектов.. выглядит как просто кортеж, с каких это пор кортеж — это список кортежей? Вопрос четко задает, как создать список, содержащий два объекта, каждый объект в списке — это два объекта, а не один объект из двух элементов.
3. @AistisTaraskevicius В первой части моего ответа говорится о кортежах как способе хранения «объектных» данных, поскольку в Groovy есть хорошие абстракции, как показано в моих примерах. Затем в последней части показано, как вы можете составить список кортежей (def tuples = [ ] << tuple << кортеж) и выполнять итерации по ним (tuples. каждый {doSomething(это) }).
Ответ №2:
Рассмотрим расширение Groovy. Например:
class Foo {}
class Bar {}
def fooBar = new Expando()
fooBar."foo" = new Foo()
fooBar."bar" = new Bar()
def fooBars = []
fooBars << fooBar
fooBars.each { item ->
def foo = item."foo"
def bar = item."bar"
assert foo instanceof Foo
assert bar instanceof Bar
}
Ответ №3:
Почему бы просто не использовать список списков? Каждый элемент списка может быть двухэлементным списком, содержащим Foo
и Bar
экземпляры в таком порядке.
Для дополнительной безопасности при построении каждого двухэлементного списка Foo / Bar напишите вспомогательный метод, который проверяется на тип и возвращает неизменяемый список, чтобы предотвратить вмешательство после построения.
@TypeChecked
def makeFooBar(Foo foo, Bar bar) {
[foo, bar].asImmutable()
}
def fooBars = []
// some code to populate the list...
fooBars << makeFooBar(new Foo(), new Bar())
// iterate and do something with each foo/bar pair
fooBars.each { fooBar ->
def (foo, bar) = fooBar
}
Одна из областей, небезопасных для типов, — это fooBars
список, который может быть заполнен другими типами объектов. Но если вы хотите такую степень безопасности типов, то, возможно, вам следует рассмотреть совсем другой язык.
Комментарии:
1. Спасибо за ваш ответ. Что вы имеете в виду, говоря «рассмотреть другой язык»? (Кстати, я родом из мира PHP) 🙂
2. Я просто имел в виду, что если вы хотите использовать общие термины и чтобы они что-то значили, вам следует рассмотреть Java вместо Groovy. Groovy, по умолчанию, строго не учитывает универсальные подписи; он с радостью выполнит код
List<Integer> list = ['hi', 'there']
. Но, на мой взгляд, лучший способ справиться с этой слабостью — принять подход Groovy и написать свой код какdef list = ['hi', 'there']
. В целом, однако, если вы подходите с точки зрения PHP, я думаю, Groovy вам хорошо подойдет.
Ответ №4:
Почему никто не предложил карту?
def x = [:]
x['foo'] = new Bar()
Кажется, это немного умнее, чем список кортежей.