portaldacalheta.pt
  • Principal
  • Vida Designer
  • Design De Marca
  • Ciclo De Vida Do Produto
  • Ferramentas E Tutoriais
Processo Interno

Um conjunto de possibilidades: um guia para correspondência de padrões Ruby



A correspondência de padrões é o grande novo recurso que chega ao Ruby 2.7. Foi entregue ao tronco para que qualquer pessoa interessada possa instalar Ruby 2.7.0-dev e dê uma olhada. Lembre-se de que nada disso foi finalizado e que a equipe de desenvolvimento está procurando feedback, portanto, se você tiver algum, informe os responsáveis ​​pelo commit antes que o recurso seja lançado.

Espero que você entenda o que é correspondência de padrões e como usá-la em Ruby depois de ler este artigo.



O que é correspondência de padrões?

A correspondência de padrões é um recurso comumente encontrado em linguagens de programação funcionais. De acordo com Escala de documentação , a correspondência de padrões é “Um mecanismo para verificar um valor em relação a um padrão. Uma combinação bem-sucedida também pode desconstruir um valor em suas partes constituintes. ”



Isso não deve ser confundido com Regex, correspondência de string ou reconhecimento de padrão. A correspondência de padrões não tem nada a ver com string, mas sim com a estrutura de dados. A primeira vez que encontrei correspondência de padrões foi há cerca de dois anos, quando experimentei Elixir . Eu estava aprendendo Elixir e tentando resolver algoritmos com ele. Eu comparei minha solução com outras e percebi que eles usavam correspondência de padrões, o que tornava seu código muito mais sucinto e fácil de ler.



Por causa disso, a combinação de padrões realmente me impressionou. É assim que a correspondência de padrões no Elixir se parece:

[a, b, c] = [:hello, 'world', 42] a #=> :hello b #=> 'world' c #=> 42

O exemplo acima se parece muito com um atribuição múltipla em Ruby. No entanto, é mais do que isso. Ele também verifica se os valores correspondem ou não:



[a, b, 42] = [:hello, 'world', 42] a #=> :hello b #=> 'world'

Nos exemplos acima, o número 42 no lado esquerdo não é uma variável que está sendo atribuída. É um valor para verificar se o mesmo elemento naquele índice específico corresponde ao do lado direito.

[a, b, 88] = [:hello, 'world', 42] ** (MatchError) no match of right hand side value

Neste exemplo, em vez dos valores sendo atribuídos, MatchError é gerado em vez disso. Isso ocorre porque o número 88 não corresponde ao número 42.



Também funciona com mapas (que é semelhante ao hash em Ruby):

%{'name': 'Zote', 'title': title } = %{'name': 'Zote', 'title': 'The mighty'} title #=> The mighty

O exemplo acima verifica se o valor da chave name é Zote e vincula o valor da chave title ao título da variável.



Este conceito funciona muito bem quando a estrutura de dados é complexa. Você pode atribuir sua variável e verificar se há valores ou tipos em uma linha.

Além disso, também permite que uma linguagem digitada dinamicamente como Elixir tenha sobrecarga de método:



def process(%{'animal' => animal}) do IO.puts('The animal is: #{animal}') end def process(%{'plant' => plant}) do IO.puts('The plant is: #{plant}') end def process(%{'person' => person}) do IO.puts('The person is: #{person}') end

Dependendo da chave do hash do argumento, métodos diferentes são executados.

Esperançosamente, isso mostra como a correspondência de padrões pode ser poderosa. Existem muitas tentativas de trazer correspondência de padrões para Ruby com joias como Noaidi , qo , e egison-ruby .



Ruby 2.7 também tem sua própria implementação não muito diferente dessas joias, e é assim que está sendo feito atualmente.

Sintaxe de correspondência de padrões Ruby

A correspondência de padrões em Ruby é feita por meio de um case declaração. No entanto, em vez de usar o usual when, a palavra-chave in é usado em seu lugar. Ele também suporta o uso de if ou unless afirmações:

case [variable or expression] in [pattern] ... in [pattern] if [expression] ... else ... end

A declaração de caso pode aceitar uma variável ou uma expressão e isso será comparado com os padrões fornecidos no dentro cláusula. E se ou a menos que instruções também podem ser fornecidas após o padrão. A verificação de igualdade aqui também usa === como a instrução de caso normal. Isso significa que você pode combinar subconjuntos e instâncias de classes. Aqui está um exemplo de como você o usa:

Matrizes correspondentes

translation = ['th', 'เต้', 'ja', 'テイ'] case translation in ['th', orig_text, 'en', trans_text] puts 'English translation: #{orig_text} => #{trans_text}' in ['th', orig_text, 'ja', trans_text] # this will get executed puts 'Japanese translation: #{orig_text} => #{trans_text}' end

No exemplo acima, a variável translation é comparado com dois padrões:

['th', orig_text, 'en', trans_text] e ['th', orig_text, 'ja', trans_text]. O que ele faz é verificar se os valores no padrão correspondem aos valores no translation variável em cada um dos índices. Se os valores corresponderem, ele atribuirá os valores em translation variável para as variáveis ​​no padrão em cada um dos índices.

Ruby Pattern Matching Animation: Matching Arrays

Hashes correspondentes

translation = {orig_lang: 'th', trans_lang: 'en', orig_txt: 'เต้', trans_txt: 'tae' } case translation in {orig_lang: 'th', trans_lang: 'en', orig_txt: orig_txt, trans_txt: trans_txt} puts '#{orig_txt} => #{trans_txt}' end

No exemplo acima, o translation variável agora é um hash. Ele é comparado com outro hash no in cláusula. O que acontece é que a instrução case verifica se todas as chaves no padrão correspondem às chaves no translation variável. Ele também verifica se todos os valores de cada chave correspondem. Em seguida, atribui os valores à variável no hash.

Ruby Pattern Matching Animation: Matching Arrays

tamanhos de tela padrão para design responsivo

Subconjuntos correspondentes

A verificação de qualidade usada na correspondência de padrões segue a lógica de ===.

Padrões múltiplos

  • | pode ser usado para definir vários padrões para um bloco.
translation = ['th', 'เต้', 'ja', 'テイ'] case array in {orig_lang: 'th', trans_lang: 'ja', orig_txt: orig_txt, trans_txt: trans_txt} | ['th', orig_text, 'ja', trans_text] puts orig_text #=> เต้ puts trans_text #=> テイ end

No exemplo acima, o translation a variável é igual a {orig_lang: 'th', trans_lang: 'ja', orig_txt: orig_txt, trans_txt: trans_txt} hash e ['th', orig_text, 'ja', trans_text] array.

Isso é útil quando você tem tipos ligeiramente diferentes de estruturas de dados que representam a mesma coisa e deseja que ambas as estruturas de dados executem o mesmo bloco de código.

Atribuição de seta

Nesse caso, => pode ser usado para atribuir um valor correspondente a uma variável.

case ['I am a string', 10] in [Integer, Integer] => a # not reached in [String, Integer] => b puts b #=> ['I am a string', 10] end

Isso é útil quando você deseja verificar os valores dentro da estrutura de dados, mas também vincular esses valores a uma variável.

Operador de alfinetes

Aqui, o operador pin impede que as variáveis ​​sejam reatribuídas.

case [1,2,2] in [a,a,a] puts a #=> 2 end

No exemplo acima, a variável a no padrão é comparada a 1, 2 e então 2. Ela será atribuída a 1, a 2 e a 2. Esta não é uma situação ideal se você quiser verificar se todos os os valores na matriz são iguais.

case [1,2,2] in [a,^a,^a] # not reached in [a,b,^b] puts a #=> 1 puts b #=> 2 end

Quando o operador pin é usado, ele avalia a variável em vez de reatribuí-la. No exemplo acima, [1,2,2] não corresponde a [a, ^ a, ^ a] porque no primeiro índice a é atribuído a 1. No segundo e terceiro, a é avaliado como 1, mas é comparado com 2.

No entanto, [a, b, ^ b] corresponde a [1,2,2], uma vez que a é atribuído a 1 no primeiro índice, b é atribuído a 2 no segundo índice, então ^ b, que agora é 2, é correspondido 2 no terceiro índice para que passe.

a = 1 case [2,2] in [^a,^a] #=> not reached in [b,^b] puts b #=> 2 end

Variáveis ​​de fora da instrução case também podem ser usadas conforme mostrado no exemplo acima.

como o python é usado em finanças

Operador de sublinhado (_)

O sublinhado (_) é usado para ignorar os valores. Vejamos alguns exemplos:

case ['this will be ignored',2] in [_,a] puts a #=> 2 end case ['a',2] in [_,a] => b puts a #=> 2 Puts b #=> ['a',2] end

Nos dois exemplos acima, qualquer valor que corresponda a _ passes. No segundo caso, => operador captura o valor que foi ignorado também.

Casos de uso para correspondência de padrões em Ruby

Imagine que você tenha os seguintes dados JSON:

{ nickName: 'Tae' realName: {firstName: 'Noppakun', lastName: 'Wongsrinoppakun'} username: 'tae8838' }

Em seu projeto Ruby, você deseja analisar esses dados e exibir o nome com as seguintes condições:

  1. Se o nome de usuário existir, retorne o nome de usuário.
  2. Se o apelido, o nome e o sobrenome existirem, retorne o apelido, o nome e o sobrenome.
  3. Se o apelido não existir, mas o nome e o sobrenome sim, retorne o nome e o sobrenome.
  4. Se nenhuma das condições se aplicar, retorne “Novo usuário”.

É assim que eu escreveria este programa em Ruby agora:

def display_name(name_hash) if name_hash[:username] name_hash[:username] elsif name_hash[:nickname] && name_hash[:realname] && name_hash[:realname][:first] && name_hash[:realname][:last] '#{name_hash[:nickname]} #{name_hash[:realname][:first]} #{name_hash[:realname][:last]}' elsif name_hash[:first] && name_hash[:last] '#{name_hash[:first]} #{name_hash[:last]}' else 'New User' end end

Agora, vamos ver como fica a correspondência de padrões:

def display_name(name_hash) case name_hash in {username: username} username in {nickname: nickname, realname: {first: first, last: last}} '#{nickname} #{first} #{last}' in {first: first, last: last} '#{first} #{last}' else 'New User' end end

A preferência de sintaxe pode ser um pouco subjetiva, mas eu prefiro a versão de correspondência de padrões. Isso ocorre porque a correspondência de padrões nos permite escrever o hash que esperamos, em vez de descrever e verificar os valores do hash. Isso torna mais fácil visualizar quais dados esperar:

`{nickname: nickname, realname: {first: first, last: last}}`

Em vez de:

`name_hash[:nickname] && name_hash[:realname] && name_hash[:realname][:first] && name_hash[:realname][:last]`.

Desconstruir e Desconstruir_chaves

Existem dois novos métodos especiais sendo introduzidos no Ruby 2.7: deconstruct e deconstruct_keys. Quando uma instância de uma classe está sendo comparada a uma matriz ou hash, deconstruct ou deconstruct_keys são chamados, respectivamente.

Os resultados desses métodos serão usados ​​para comparar os padrões. Aqui está um exemplo:

class Coordinate attr_accessor :x, :y def initialize(x, y) @x = x @y = y end def deconstruct [@x, @y] end def deconstruct_key {x: @x, y: @y} end end

O código define uma classe chamada Coordinate. Possui xey como atributos. Ele também tem deconstruct e deconstruct_keys métodos definidos.

c = Coordinates.new(32,50) case c in [a,b] p a #=> 32 p b #=> 50 end

Aqui, uma instância de Coordinate está sendo definido e o padrão combinado com uma matriz. O que acontece aqui é que Coordinate#deconstruct é chamado e o resultado é usado para corresponder ao array [a,b] definido no padrão.

case c in {x:, y:} p x #=> 32 p y #=> 50 end

Neste exemplo, a mesma instância de Coordinate está sendo correspondido por padrão a um hash. Nesse caso, o Coordinate#deconstruct_keys resultado é usado para comparar com o hash {x: x, y: y} definido no padrão.

Um recurso experimental empolgante

Tendo experimentado a correspondência de padrões pela primeira vez no Elixir, pensei que esse recurso poderia incluir sobrecarga de método e implementado com uma sintaxe que requer apenas uma linha. No entanto, Ruby não é uma linguagem construída com o casamento de padrões em mente, então isso é compreensível.

Usar uma instrução case é provavelmente uma maneira muito enxuta de implementar isso e também não afeta o código existente (além dos métodos deconstruct e deconstruct_keys). O uso da instrução case é realmente semelhante ao da implementação de correspondência de padrões do Scala.

Pessoalmente, acho que a correspondência de padrões é um recurso novo e interessante para Desenvolvedores Ruby . Ele tem o potencial de tornar o código muito mais limpo e fazer o Ruby parecer um pouco mais moderno e excitante. Eu adoraria ver o que as pessoas pensam disso e como esse recurso evoluirá no futuro.

Compreender o básico

O que é correspondência de padrões na programação funcional?

De acordo com a documentação do Scala, a correspondência de padrões é “um mecanismo para verificar um valor em relação a um padrão. Uma combinação bem-sucedida também pode desconstruir um valor em suas partes constituintes. ”

Por que a correspondência de padrões é útil?

Ele tem o potencial de tornar o código muito mais limpo e fazer o Ruby parecer um pouco mais moderno e excitante.

Como funciona a correspondência de padrões?

Por meio da instrução switch case em Ruby 2.7, usando a palavra-chave 'in' em vez do usual 'when'.

O que significa correspondência de padrões?

De acordo com a documentação do Scala, a correspondência de padrões é “um mecanismo para verificar um valor em relação a um padrão. Uma combinação bem-sucedida também pode desconstruir um valor em suas partes constituintes. ”

Engenheiro de back-end sênior, equipe Armani

De Outros

Engenheiro de back-end sênior, equipe Armani
Qualidade dos ganhos: um pilar fundamental da devida diligência financeira

Qualidade dos ganhos: um pilar fundamental da devida diligência financeira

Processos Financeiros

Publicações Populares
Rede Al-Jazeera America é encerrada hoje
Rede Al-Jazeera America é encerrada hoje
Por que as moedas dos mercados emergentes são voláteis?
Por que as moedas dos mercados emergentes são voláteis?
Um pai compartilha sua jornada pessoal ao lidar com uma filha disléxica
Um pai compartilha sua jornada pessoal ao lidar com uma filha disléxica
Você precisa de um herói: o gerente de projeto
Você precisa de um herói: o gerente de projeto
Folha de dicas de CSS rápida e prática do ApeeScape
Folha de dicas de CSS rápida e prática do ApeeScape
 
Tutorial OpenCV: Detecção de objetos em tempo real usando MSER no iOS
Tutorial OpenCV: Detecção de objetos em tempo real usando MSER no iOS
Discurso de Barack Obama marca contagem regressiva não oficial para americanos negros
Discurso de Barack Obama marca contagem regressiva não oficial para americanos negros
Arquitetura orientada a serviços com AWS Lambda: um tutorial passo a passo
Arquitetura orientada a serviços com AWS Lambda: um tutorial passo a passo
Dez principais regras de design de front-end para desenvolvedores
Dez principais regras de design de front-end para desenvolvedores
UE adia negociações comerciais com a Austrália em meio a negociações de submarinos
UE adia negociações comerciais com a Austrália em meio a negociações de submarinos
Publicações Populares
  • programação de computador c ++
  • c ++ aprender fazendo
  • você está montando um sistema para um artista gráfico
  • documento de design técnico para aplicativo móvel
  • diferença entre c corporation e s
Categorias
  • Vida Designer
  • Design De Marca
  • Ciclo De Vida Do Produto
  • Ferramentas E Tutoriais
  • © 2022 | Todos Os Direitos Reservados

    portaldacalheta.pt