Ceci est un vieux fil et je pense que les autres réponses sont excellentes, mais oubliez quelque chose, alors voici mes (tardifs) 2 cents.
Le revêtement de sucre syntactique cache la complexité
Le problème avec les chaînes est qu'elles sont des citoyens de seconde classe dans la plupart des langues, et ne sont en fait pas la plupart du temps une partie de la spécification de la langue elle-même: elles sont une construction implémentée par la bibliothèque avec une couche de sucre syntaxique occasionnelle sur le dessus pour les rendre moins pénibles à utiliser.
La conséquence directe de cela est que le langage cache une très grande partie de leur complexité à votre vue, et vous payez pour les effets secondaires sournois parce que vous avez l'habitude de les considérer comme une entité atomique de bas niveau, tout comme d'autres types primitifs (comme expliqué par la réponse la plus votée et d'autres).
Détails d'implémentation
Good Ol 'Array
Un des éléments de cette "complexité" sous-jacente est que la plupart des implémentations de chaînes auraient recours à une structure de données simple avec un espace mémoire contigu pour représenter la chaîne: votre bon vieux tableau.
Cela a du sens, sachez que vous voulez que l'accès à la chaîne dans son ensemble soit rapide. Mais cela implique des coûts potentiellement terribles lorsque vous souhaitez manipuler cette chaîne. L'accès à un élément au milieu peut être rapide si vous savez quel index vous recherchez , mais pas la recherche d'un élément basé sur une condition.
Même le retour de la taille de la chaîne peut être coûteux, si votre langue ne met pas en cache la longueur de la chaîne et doit la parcourir pour compter les caractères.
Pour des raisons similaires, l' ajout d' éléments à votre chaîne s'avérera coûteux car vous devrez probablement réallouer de la mémoire pour que cette opération se produise.
Ainsi, différentes langues adoptent des approches différentes à ces problèmes. Java, par exemple, a pris la liberté de rendre ses chaînes immuables pour des raisons valables (longueur de mise en cache, sécurité des threads) et pour ses homologues mutables (StringBuffer et StringBuilder) choisiront d'allouer la taille en utilisant des morceaux de plus grande taille pour ne pas avoir besoin d'allouer à chaque fois, mais espérez plutôt les meilleurs scénarios. Cela fonctionne généralement bien, mais l'inconvénient est parfois de payer pour les impacts sur la mémoire.
Prise en charge Unicode
De plus, et encore une fois, cela est dû au fait que le revêtement de sucre syntaxique de votre langue vous le cache pour jouer bien, vous ne le pensez souvent pas en termes de support unicode (surtout aussi longtemps que vous n'en avez pas vraiment besoin). et a frappé ce mur). Et certains langages, étant avant-gardistes, n'implémentent pas de chaînes avec des tableaux sous-jacents de simples primitives char 8 bits. Ils ont cuit en UTF-8 ou UTF-16 ou ce que vous avez en charge, et la conséquence est une consommation de mémoire considérablement plus grande, qui n'est souvent pas nécessaire, et un temps de traitement plus long pour allouer de la mémoire, traiter les chaînes, et implémenter toute la logique qui va de pair avec la manipulation des points de code.
Le résultat de tout cela, c'est que lorsque vous faites quelque chose d'équivalent en pseudo-code pour:
hello = "hello,"
world = " world!"
str = hello + world
Il se peut que ce ne soit pas - malgré tous les efforts que les développeurs de langage mettent en œuvre pour les faire se comporter comme vous le feriez sauf - aussi simple que:
a = 1;
b = 2;
shouldBeThree = a + b
À titre de suivi, vous voudrez peut-être lire: