Eu li Funções do Scala (parte de Outra turnê do Scala ). Nesse post, ele declarou:
Métodos e funções não são a mesma coisa
Mas ele não explicou nada sobre isso. O que ele estava tentando dizer?
Eu li Funções do Scala (parte de Outra turnê do Scala ). Nesse post, ele declarou:
Métodos e funções não são a mesma coisa
Mas ele não explicou nada sobre isso. O que ele estava tentando dizer?
Respostas:
Jim tem isso praticamente coberto em seu blog , mas estou postando um briefing aqui para referência.
Primeiro, vamos ver o que a especificação Scala nos diz. O Capítulo 3 (tipos) nos fala sobre Tipos de Função (3.2.9) e Tipos de Método (3.3.1). O Capítulo 4 (declarações básicas) fala de Declaração e Definições de Valor (4.1), Declaração e Definições Variáveis (4.2) e Declarações e Definições de Funções (4.6). O capítulo 6 (expressões) fala de funções anônimas (6.23) e valores de métodos (6.7). Curiosamente, os valores das funções são falados uma vez no 3.2.9, e nenhum outro lugar.
Um Tipo de Função é (aproximadamente) um tipo do formulário (T1, ..., Tn) => U , que é uma abreviação para a característica
FunctionN
na biblioteca padrão. Funções anônimas e valores de método têm tipos de função, e os tipos de função podem ser usados como parte do valor, das declarações e definições de variáveis e funções. De fato, ele pode fazer parte de um tipo de método.Um Tipo de método é um tipo sem valor . Isso significa que não há valor - nenhum objeto, nenhuma instância - com um tipo de método. Como mencionado acima, um valor de método realmente tem um tipo de função . Um tipo de método é uma
def
declaração - tudo sobre a,def
exceto seu corpo.Valor declarações e definições e declarações variáveis e definições são
val
evar
declarações, incluindo tanto o tipo eo valor - que pode ser, respectivamente, tipo de função e anônimos funções ou valores Método . Observe que, na JVM, esses (valores de método) são implementados com o que Java chama de "métodos".Uma declaração de função é uma
def
declaração, incluindo tipo e corpo . A parte do tipo é o Tipo de método e o corpo é uma expressão ou um bloco . Isso também é implementado na JVM com o que Java chama de "métodos".Finalmente, uma função anônima é uma instância de um tipo de função (ou seja, uma instância da característica
FunctionN
), e um valor de método é a mesma coisa! A distinção é que um valor de método é criado a partir de métodos, postfixando um sublinhado (m _
é um valor de método correspondente à "declaração de função" (def
)m
) ou por um processo chamado eta-expansão , que é como uma conversão automática do método funcionar.Isso é o que dizem as especificações, então deixe-me colocar isso de frente: não usamos essa terminologia! Isso gera muita confusão entre a chamada "declaração de função" , que faz parte do programa (capítulo 4 - declarações básicas) e "função anônima" , que é uma expressão, e "tipo de função" , que é, bem um tipo - uma característica.
A terminologia abaixo, e usada por programadores Scala experientes, faz uma alteração na terminologia da especificação: em vez de dizer a declaração da função , dizemos método . Ou mesmo declaração de método. Além disso, notamos que declarações de valor e declarações de variáveis também são métodos para fins práticos.
Portanto, dada a mudança acima na terminologia, aqui está uma explicação prática da distinção.
Uma função é um objecto que inclui uma das
FunctionX
características, tais comoFunction0
,Function1
,Function2
, etc. Pode-se incluindoPartialFunction
, assim, que, na verdade, se estendeFunction1
.Vamos ver a assinatura do tipo para uma dessas características:
Essa característica tem um método abstrato (também tem alguns métodos concretos):
E isso nos diz tudo o que há para saber sobre isso. Uma função possui um
apply
método que recebe N parâmetros dos tipos T1 , T2 , ..., TN e retorna algo do tipoR
. É contra-variante nos parâmetros que recebe e co-variante no resultado.Essa variação significa que a
Function1[Seq[T], String]
é um subtipo deFunction1[List[T], AnyRef]
. Ser um subtipo significa que pode ser usado no lugar dele. Pode-se ver facilmente que, se vou ligarf(List(1, 2, 3))
e esperar umaAnyRef
resposta, qualquer um dos dois tipos acima funcionaria.Agora, qual é a semelhança de um método e uma função? Bem, se
f
é uma função em
é um método local para o escopo, ambos podem ser chamados assim:Essas chamadas são realmente diferentes, porque a primeira é apenas um açúcar sintático. Scala a expande para:
Que, é claro, é uma chamada de método ao objeto
f
. As funções também têm outros açúcares sintáticos a seu favor: literais de função (dois deles, na verdade) e(T1, T2) => R
assinaturas de tipo. Por exemplo:Outra semelhança entre um método e uma função é que o primeiro pode ser facilmente convertido no último:
O Scala expandirá isso , assumindo que o
m
tipo seja(List[Int])AnyRef
(Scala 2.7):No Scala 2.8, ele realmente usa uma
AbstractFunction1
classe para reduzir o tamanho das classes.Observe que não é possível converter o contrário - de uma função para um método.
Os métodos, no entanto, têm uma grande vantagem (bem, duas - eles podem ser um pouco mais rápidos): eles podem receber parâmetros de tipo . Por exemplo, embora
f
acima possa necessariamente especificar o tipo deList
recebimento (List[Int]
no exemplo),m
pode parametrizar:Acho que isso cobre tudo, mas terei prazer em complementar isso com respostas a quaisquer perguntas que possam permanecer.
fonte
val f = m
pelo compilador, comoval f = new AnyRef with Function1[List[Int], AnyRef] { def apply(x$1: List[Int]) = this.m(x$1) }
você deve apontar que othis
interior doapply
método não se refere aoAnyRef
objeto, mas ao objeto em cujo método oval f = m _
é avaliado (o externothis
, por assim dizer) ), uma vez quethis
está entre os valores capturados pelo fechamento (como por exemplo,return
conforme indicado abaixo).Uma grande diferença prática entre um método e uma função é o que
return
significa.return
sempre retorna de um método. Por exemplo:Retornar de uma função definida em um método gera um retorno não local:
Considerando que retornar de um método local somente retorna desse método.
fonte
for (a <- List(1, 2, 3)) { return ... }
? Isso é retirado do açúcar até o fechamento.return
devolver um valor da função, e alguma forma deescape
oubreak
oucontinue
para voltar a partir de métodos.Programação no Scala Second Edition. Martin Odersky - Colher Lex - Bill Venners
fonte
Vamos dizer que você tem uma lista
Definir um método
Definir uma função
Método de aceitação de argumento
Definindo Função com val
O argumento para funcionar é opcional
O argumento para o método é obrigatório
Verifique o tutorial a seguir, que explica a passagem de outras diferenças com exemplos, como outro exemplo de diff, com o método Vs Function, Using function as Variables, criando a função que retornou a função
fonte
As funções não suportam padrões de parâmetro. Métodos fazem. A conversão de um método para uma função perde os padrões dos parâmetros. (Scala 2.8.1)
fonte
Há um belo artigo aqui, do qual a maioria das minhas descrições são tiradas. Apenas uma pequena comparação de Funções e Métodos em relação ao meu entendimento. Espero que ajude:
Funções : Eles são basicamente um objeto. Mais precisamente, funções são objetos com um método apply; Portanto, eles são um pouco mais lentos que os métodos por causa de sua sobrecarga. É semelhante aos métodos estáticos no sentido de que eles são independentes de um objeto a ser invocado. Um exemplo simples de uma função é como abaixo:
A linha acima não é nada, exceto atribuir um objeto a outro, como objeto1 = objeto2. Na verdade, o objeto2 em nosso exemplo é uma função anônima e o lado esquerdo obtém o tipo de um objeto por causa disso. Portanto, agora f1 é um objeto (Função). A função anônima é na verdade uma instância da Função1 [Int, Int] que significa uma função com 1 parâmetro do tipo Int e valor de retorno do tipo Int. Chamar f1 sem os argumentos nos dará a assinatura da função anônima (Int => Int =)
Métodos : Eles não são objetos, mas atribuídos a uma instância de uma classe, ou seja, um objeto. Exatamente o mesmo que o método em java ou funções-membro em c ++ (como Raffi Khatchadourian apontou em um comentário a esta pergunta ) e etc. Um exemplo simples de método é o seguinte:
A linha acima não é uma atribuição simples de valor, mas uma definição de um método. Quando você chama esse método com o valor 2 como a segunda linha, x é substituído por 2 e o resultado será calculado e você obtém 4 como saída. Aqui você receberá um erro se simplesmente escrever m1 porque é um método e precisa do valor de entrada. Usando _, você pode atribuir um método a uma função como abaixo:
fonte
Aqui está um ótimo post de Rob Norris, que explica a diferença, aqui está um TL; DR
com a seguinte definição:
Em poucas palavras ( extrato do blog ):
Quando definimos um método, vemos que não podemos atribuí-lo a a
val
.Observe também o tipo de
add1
, que não parece normal; você não pode declarar uma variável do tipo(n: Int)Int
. Métodos não são valores.No entanto, adicionando o operador postfix de expansão η (η é pronunciado “eta”), podemos transformar o método em um valor de função. Anote o tipo de
f
.O efeito de
_
é executar o equivalente ao seguinte: construímos umaFunction1
instância que delega ao nosso método.fonte
No Scala 2.13, diferentemente das funções, os métodos podem receber / retornar
No entanto, essas restrições são levantadas em dotty (Scala 3) pelos tipos de função polimórficos # 4672 , por exemplo, a versão 0.23.0-RC1 dotty habilita a seguinte sintaxe
Parâmetros de tipo
Parâmetros implícitos ( parâmetros de contexto )
Tipos dependentes
Para mais exemplos, consulte tests / run / polymorphic-functions.scala
fonte
Praticamente, um programador Scala precisa conhecer apenas as três regras a seguir para usar funções e métodos corretamente:
def
e literais de função definidos por=>
são funções. Está definido na página 143, capítulo 8 do livro de programação em Scala, 4ª edição.someNumber.foreach(println)
Após quatro edições da Programação em Scala, ainda é um problema para as pessoas diferenciarem os dois conceitos importantes: função e valor da função, porque todas as edições não dão uma explicação clara. A especificação da linguagem é muito complicada. Eu descobri que as regras acima são simples e precisas.
fonte