Iniciante - Pq não compila de um jeito e compila do outro?

19 views
Skip to first unread message

Paulo Sales

unread,
Apr 4, 2016, 5:56:30 PM4/4/16
to scaladores
Olá pessoal,

Sou novo em Scala, mas sou programador Java há um tempo já.
Estou entrando na comunidade Scala agora e fazendo um curso na GlobalCode.

Tive uma dúvida que o instutor não conseguiu me explicar muito bem, gostaria de saber se vocês podem me dar um help :)

**Não é nada importante** só curiosidade mesmo.

Segue minha dúvida em forma de código:

// file script.scala
case class Aluno(nome:String, email:String)

object AlunoDao {
   def todos = List(
     Aluno("Test1", "te...@test.com"),
     Aluno("Test2", "te...@test.com"),
     Aluno("Test3", "te...@test.com")
   )

   def porEmail(email:String): Option[Aluno] = {
     // Usando find, impl bonita e elegante
     // AlunoDao.todos.find(a => a.email == email)

     // Dessa forma nao funciona
     // AlunoDao.todos.filter(a => a.email == email).map(a => Option(a))(0)

     // Assim funciona
     // AlunoDao.todos.filter(a => a.email == email).map(a => Option(a)).apply(0)

     // Usando uma var aux funciona sem o apply explicito
     val r = AlunoDao.todos.filter(a => a.email == email).map(a => Option(a))
     r(0)
   }
}

println(AlunoDao.porEmail("te...@test.com"))


Espero que eu tenha sido claro, se eu não fui podem me metralhar de perguntas!!! :D

Obrigado à todos envolvidos nessa comunidade e por disponibilizar esse espaço para Jedis Scala e Padawans Scala :)






val Aluno[Iniciante] = responsta(pergunta(sintax()))

Gustavo Amigo

unread,
Apr 4, 2016, 6:06:53 PM4/4/16
to scaladores
Paulo,

Só usar o headOption no lugar do map(a => Option(a)).apply(0)

[]'s
Gustavo


--
You received this message because you are subscribed to the Google Groups "scaladores" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scaladores+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Paulo Sales

unread,
Apr 4, 2016, 6:27:28 PM4/4/16
to scaladores
Oi Gustavo,

Muito obrigado pela resposta, o #headOption retorna um Option[A] assim como o #find.]

Minha pergunta é relacionada à linguagem em sí, pq a linha abaixo compila:

val resultado = AlunoDao.alunos.filter(_.email == email).map(Option(_))
resultado(0)

e a linha abaixo não compila:

AlunoDao.alunos.filter(_.email == email).map(Option(_))(0)

e essa outra também compila, rs:

AlunoDao.alunos.filter(_.email == email).map(Option(_)).apply(0)

Pq o #apply implícito não é resolvido no caso que não compila, tem alguma particularidade nesse caso?

Desculpem sou novo na linguagem, mas sou chato em conhecer bem uma linguagem.

:D
}

println(AlunoDao.porEmail("test...@test.com"))


Espero que eu tenha sido claro, se eu não fui podem me metralhar de perguntas!!! :D

Obrigado à todos envolvidos nessa comunidade e por disponibilizar esse espaço para Jedis Scala e Padawans Scala :)






val Aluno[Iniciante] = responsta(pergunta(sintax()))

Maurício Szabo

unread,
Apr 4, 2016, 6:38:41 PM4/4/16
to scala...@googlegroups.com
Paulo, primeiramente, você precisará entrar na documentação de Scala (API docs) na parte de List. Lá, procura a função "map", e pede a "Full Signature": http://www.scala-lang.org/api/current/#scala.collection.immutable.List

A assinatura total do método será: 
final def map[BThat](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], BThat])That

Resumindo: "map" é uma função que recebe um parâmetro. Esse parâmetro é uma função, que para uma List[A], mapeia A => B, retornando............ bom, aqui as coisas ficam complicadas hahahahaha.

Em Scala, "map" recebe dois parâmetros, na forma de "curried function", isso é, "map" recebe um parâmetro, que retorna uma função, que recebe um parâmetro, que retorna o resultado da função. E esse segundo parâmetro é passado de forma "implícita". Esse segundo parâmetro é um construtor que sabe construir "That", a partir do "B", partindo de uma "List[A]". Confuso? Calma lá rs.


Quando você pede: 
AlunoDao.todos.filter(a => a.email == email).map(a => Option(a))(0)

Na verdade, você está passando o "0" para o SEGUNDO PARAMETRO do map. Mas então, qual seria o segundo parâmetro? Bom, também é "fácil" de descobrir: o erro de compilação é:

<console>:9: error: type mismatch;
found   : Int(0)
required: scala.collection.generic.CanBuildFrom[List[Aluno],Option[Aluno],?]

Ou seja, o segundo parâmetro era para ser um scala.collection.generic.CanBuildFrom[List[Aluno],Option[Aluno],?].

Repare no "?" no final - é que ele não sabe direito o que você está pedindo, já que o builder não foi passado. Bom, a gente sabe que o resultado do seu map é uma "List[Option[Aluno]]", logo, o terceiro tipo é um "List[Option[Aluno]]", porque se a gente olhar na assinatura do Map, vai ver que o terceiro tipo que o CanBuildFrom pede chama "That", e o retorno do map é um That. Então, é só passar o builder apropriado.

Como sabemos qual o builder apropriado? Podemos usar "implicitly": 

val builder = implicitly[scala.collection.generic.CanBuildFrom[List[Aluno],Option[Aluno],List[Option[Aluno]]]]

Isso vai retornar um 
scala.collection.generic.GenTraversableFactory

Aí, é só passar esse builder para seu map: 
AlunoDao.todos.filter(a => a.email == email).map(a => Option(a))(builder)(0)

Bom, essa é a explicação completa rs. Agora, a explicação simples:

Map é uma função que retorna uma função. Essa segunda função pede um "builder", de forma implícita. Se nada for passado, ele implicitamente escolhe um, e retorna um List. Só então, o método "map" resolve, e aí você pode usar o "apply" da List.

Logo:
AlunoDao.todos.filter(a => a.email == email).map(a => Option(a)).apply(0)
                                                                ^-- Segundo parâmetro não foi passado, 
                                                                    usa o implícito, que retorna uma List.

val r = AlunoDao.todos.filter(a => a.email == email).map(a => Option(a))
                                                                        ^-- Segundo parâmetro não foi passado,
                                                                            usa o implícito.
r(0) <-- Isso aqui é uma List, já.


AlunoDao.todos.filter(a => a.email == email).map(a => Option(a))(0)
                                                                 ^-- Segundo parâmetro FOI passado, mas não
                                                                     atende ao tipo CanBuildFrom... Erro!

Espero ter ajudado! Qualquer dúvida, só falar :D

---
A question that sometimes drives me hazy: am I or are the others crazy?
(Albert Einstein)

Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction. 
(E. F. Schumacher)

It seems to me that measuring maturity is a very immature thing to do. Teens talk about their maturity, adults don't.
(Robert Martin)

Apenas peixes mortos nadam a favor da maré 
(Malcolm Muggeridge)

Paulo Sales

unread,
Apr 4, 2016, 6:51:14 PM4/4/16
to scaladores
Oi Mauricio,

Nossa agora sim ficou muito claro, muito mesmo! rsrs

Gratidão pela exímia resposta :D :D :D

Até a próxima!

P.S.: Gostei das frases na sua assinatura rs
}

println(AlunoDao.porEmail("test...@test.com"))


Espero que eu tenha sido claro, se eu não fui podem me metralhar de perguntas!!! :D

Obrigado à todos envolvidos nessa comunidade e por disponibilizar esse espaço para Jedis Scala e Padawans Scala :)






val Aluno[Iniciante] = responsta(pergunta(sintax()))

--
You received this message because you are subscribed to the Google Groups "scaladores" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scaladores+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages