web-dev-qa-db-fra.com

to_s vs to_str (et to_i / to_a / to_h vs to_int / to_ary / to_hash) dans Ruby

J'apprends Ruby et j'ai vu quelques méthodes qui me déroutent un peu, en particulier to_s contre to_str (et de même, to_i/to_int, to_a/to_ary, & to_h/to_hash). Ce que j'ai lu explique que le formulaire plus court (par exemple to_s) sont pour les conversions explicites tandis que la forme plus longue est pour les conversions implicites.

Je ne comprends pas vraiment comment to_str serait effectivement utilisé. Est-ce que quelque chose d'autre qu'une chaîne définirait jamais to_str? Pouvez-vous donner une application pratique pour cette méthode?

64
Jeff Storey

Notez d'abord que tout cela s'applique à chaque paire de "short" (par exemple to_s/to_i/to_a/to_h) vs "long" (par exemple to_str/to_int/to_ary/to_hash) méthodes de coercition dans Ruby (pour leurs types respectifs) car elles ont toutes la même sémantique.


Ils ont des significations différentes. Vous ne devez pas implémenter to_str sauf si votre objet agit comme une chaîne, plutôt que d'être simplement représentable par une chaîne. La seule classe principale qui implémente to_str est String lui-même.

De Programmation Ruby (cité de ce billet de blog , qui vaut la peine d'être lu tout):

[to_i et to_s] ne sont pas particulièrement stricts: si un objet a une sorte de représentation décente sous forme de chaîne, par exemple, il aura probablement un to_s méthode… [to_int et to_str] sont des fonctions de conversion strictes: vous ne les implémentez que si [votre] objet peut naturellement être utilisé à chaque endroit où une chaîne ou un entier pourrait être utilisé.

Ancienne Ruby de la pioche a ceci à dire:

Contrairement à to_s, qui est pris en charge par presque toutes les classes, to_str n'est normalement implémenté que par les classes qui agissent comme des chaînes.

Par exemple, en plus de Entier , les deux Flottant & Numérique implémentent to_int (to_i est l'équivalent de to_str) parce que les deux peuvent facilement remplacer un nombre entier (ils sont tous en fait des nombres). À moins que votre classe n'ait une relation similaire avec String, vous ne devez pas implémenter to_str.

77
Andrew Marshall

Pour comprendre si vous devez utiliser/implémenter to_s/to_str, Regardons quelques exemples. Il est révélateur de considérer lorsque ces méthodes échouent.

1.to_s              # returns "1"
Object.new.to_s     # returns "#<Object:0x4932990>"
1.to_str            # raises NoMethodError
Object.new.to_str   # raises NoMethodError

Comme nous pouvons le voir, to_s Est heureux de transformer n'importe quel objet en une chaîne. D'un autre côté, to_strdéclenche une erreur lorsque son paramètre ne ressemble pas à une chaîne.


Voyons maintenant Array#join.

[1,2].join(',')     # returns "1,2"
[1,2].join(3)       # fails, the argument does not look like a valid separator.

Il est utile que Array#join Soit converti pour enchaîner les éléments du tableau (quels qu'ils soient réellement) avant de les joindre, donc Array#join Appelle to_s Sur eux.

Cependant, le séparateur est censé être une chaîne - quelqu'un qui appelle [1,2].join(3) est susceptible de faire une erreur. C'est pourquoi Array#join Appelle to_str Sur le séparateur.


Le même principe semble s'appliquer aux autres méthodes. Considérez to_a/to_ary Sur un hachage:

{1,2}.to_a      # returns [[1, 2]], an array that describes the hash
{1,2}.to_ary    # fails, because a hash is not really an array.

En résumé, voici comment je le vois:

  • appelez to_s pour obtenir une chaîne décrivant l'objet.
  • appelez to_str pour vérifier qu'un objet agit vraiment comme une chaîne.
  • implémentez to_s lorsque vous pouvez créer une chaîne décrivant votre objet.
  • implémentez to_str lorsque votre objet peut se comporter complètement comme une chaîne.

Je pense qu'un cas où vous pourriez implémenter to_str Vous-même est peut-être une classe ColoredString - une chaîne qui a une couleur attachée. S'il vous semble clair que passer une virgule colorée à join n'est pas une erreur et devrait entraîner "1,2" (Même si cette chaîne ne serait pas colorée), alors faire implémenter to_str sur ColoredString.

19
Eldritch Conundrum

Zverok a un excellent article facilement compréhensible sur quand utiliser quoi (expliqué avec to_h et to_hash).

Il doit déterminer si votre objet implémentant ces méthodes peut être converti en chaîne -> utiliser to_s
ou il s'agit d'un type de chaîne (améliorée) -> utilisez to_str


J'ai vu une utilisation significative de to_hash en pratique pour la classe Configuration dans la gemme 'configuration' ( GitHub et Configuration.rb )

Il représente - comme son nom l'indique - la configuration fournie, qui est en fait une sorte de hachage (avec des fonctionnalités supplémentaires), plutôt que d'être convertible en une seule.

0
dCSeven