특정 값을 문자열로 저장하는 것은 나쁜 습관입니까?


19

매우 모호한 제목이지만 더 나은 표현 방법을 생각할 수 없었습니다. 그러나 예를 들어 게임의 캐릭터가 움직이는 방향에 대해 생각하십시오. 문자열을 사용하고 다음과 같은 일을하는 것은 잘못된 느낌 if(character.direction == "left")입니다. 실수로 사용하는 바보 같은 오류에 대해 너무 많은 공간, 단풍 나에게 보인다 Left거나 l또는 무엇이든 대신을 left. 내 의심이 맞습니까? 그렇다면, 이와 같은 것을 달성하기 위해 선호되는 방법은 무엇입니까?


10
당신의 언어가 그것들을 지원한다면 열거 형 외에?
hoffmale

12
당신은 문자열 타입을 의미 합니까?
RubberDuck


일부 언어는 문자열 이외의 값을 저장할 수 없습니다 (예 :) bash.
mouviciel

왜 그런지 모르겠지만 C에서 "define"을 기억했습니다. 다음과 같은 작업을 수행 할 수 있습니다. #define false true
linuxunil

답변:


28

사용중인 언어가 열거 형 사용을 지원하면 해당 언어를 사용합니다. 주어진 유형에 사용 가능한 옵션의 수를 제한 할 수 있습니다. 예를 들어 Java에서 :

public enum Direction {
    LEFT,
    RIGHT,
    UP,
    DOWN
}

2
이 답변은 OP 문제 이해에 기여하지 않습니다. 나는 여기서 추론을 보지 못하고, enum자바와 같은 고급스러운 언어로 범위가 제한된 의견 만 . 많은 언어 (예 : VBA)에는가 enum있지만 미래 보장 기능이 동일하지 않으므로 최선의 선택이 아닐 수 있습니다. 왜 enum혼자가 불완전하고 종종 취하기 쉬운 언어 별 솔루션 인지에 대한 토론을 보려면 내 대답을 참조하십시오 .
sqykly

12

코드에서 리터럴 문자열 (또는 매직 숫자)을 사용하는 것은 끔찍한 연습입니다.

열거 형은 좋거나 최소한 상수를 사용합니다 (물론 열거 형은 하나 이상의 관련 상수에 대한 래퍼 유형 일뿐입니다).

const string LEFT = "left"
if (someThing == LEFT) { doStuff(); }

이 간단한 스위치는 (어떤 커피를 더하지 않으면 서) 어디서 설명해야할지조차 모르는 많은 장점을 가지고 있습니다. 마법의 숫자를 읽으십시오. 동일한 개념이며 문자열 값 대신 숫자 값에만 적용됩니다.

여기에 하나의 빠른 참조가 있습니다. 수백 가지가 더 있다고 확신합니다 : https : //.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad


1
이 접근 방식의 문제점은 --const string LEFT = "letf"와 같은 오타 버그를 얻는 반면 컴파일 타임에 잡히는 열거 형으로 작업하는 경우입니다.
Pieter B

@PieterB-OP 질문이 충분히 광범위하다고 생각하고 "왼쪽"에 대한 예는 임의의 예입니다-모든 경우가 열거 형과 일치하지 않습니다. 나는 구체적으로 일련의 지시 사항에 대해 열거 형이 최선의 선택이지만 내 대답은 "당신이 문자 그대로 넣으면 적어도 일정하게 유지하십시오"(물론 열거 형) 상수의 유형이 됨)
jleach

3
주말이 "s"로 시작하는 요일로 지정된 응용 프로그램을 사용하여 작업하는 것이 즐거웠습니다. 그들이 프랑스가 하루 주말 만 가지고있는 응용 프로그램을 국제화 할 때 "사실"에 대해 놀랐습니다.
Pieter B

4
그것을 미세 최적화라고 부르지 만 일부 언어는 이것을 값 비교로 해석하고 문자열의 각 문자를 검사하는 데 많은 시간을 낭비 할 수 있습니다. asker가했던 것처럼하고 코드화 된 문자열 인 "left"와 비교한다면 더욱 그렇습니다. 상수 값이 문자열 일 필요가 없으면 (즉, 인쇄하지 않음) const int를 대신 사용하는 것이 좋습니다.
Devsman

4

짧은 대답 : 예, 문자열은 일련의 텍스트 문자를 저장하고 액세스하는 것 이외의 작업에 이상적이지 않으며 추상화의 기본 비트가 문자열 인 경우에도 변수를 상수 또는 상수로 참조하면 이점이 있습니다 .

긴 대답 : 대부분의 언어는 문제의 영역에 더 가까운 유형을 제공하며 그렇지 않은 경우에도 (등 등) left다른 엔티티로 정의 할 수있는 방법이있을 수 있습니다 right. 사용하여 문자열로 바꾸는 "left"것은 단순히 언어와 오류 확인과 같은 IDE의 유용한 기능을 상실한 것입니다. 당신이 사용해야하더라도

left = "left";

또는 이와 동등한 것으로 코드에서 문자열을 참조 할 때 문자열을 사용하는 것이 좋습니다. 예를 들어

if (player.direction == Left)

컴파일 타임 오류 (최고의 경우, Java 등)로 감지되거나 비트가 잘못된 IDE (최악의 경우, 기본 등)로 플래그가 지정됩니다.

또한 left참조 가능한 엔티티 라는 개념을 사용하면 방향 유형으로 가기로 결정한 방향을 수용하는 데 도움이됩니다. 을 사용 "left"하면 방향이으로 커밋됩니다 String. 유형에 대한 더 나은 추상화를 찾거나 작성하는 경우의 모든 인스턴스를 변경하는 전체 코드 본문을 탐색해야합니다 "left". 유형이 정교하면 상수 또는 변수를 변경할 필요가 없습니다.

실제로 원하는 유형은 도메인에 따라 다릅니다. 귀하의 코드는 무엇을 할 계획 left입니까? 아마도 왼쪽을 향하거나 앞으로 움직이는 텍스처 또는 스프라이트의 x 축을 대칭 시키려고 할 것입니다. 그렇다면 객체가 미러되지 않은 결과를 가져 left와서 해당 동작을 반영하는 속성 또는 메서드로 객체 를 만들 수 right있습니다. 스프라이트 또는 텍스처를 나타내는 객체에서 해당 논리를 수행 할 수 있습니다.이 경우 위에서 언급 한 이유 "left"대신 다시 사용하면 문제가 발생합니다 left.

Java에서는 (아직 모르는 다른 언어), enumJava에서는 유한 한 인스턴스 집합에 enum유용 하기 때문에 좋은 대안 final class입니다. 필요한 경우 비헤이비어를 정의 할 수 있으며 파일 외부에서을 선언하는 번거 로움없이 개방형 클래스로 전환 할 수 enum있지만 많은 언어 enum가 프리미티브 유형으로 보거나 특수 구문을 사용해야합니다. 이로 인해 enum비즈니스에 관여하지 않는 코드로 인해 후드가 유출되어 나중에 수정해야 할 수도 있습니다. enum옵션을 고려하기 전에 언어의 개념을 이해해야합니다 .


2

언어를 지정하지 않았지만 일반적인 대답을 제공하려면 실제로 텍스트가 필요할 때 무언가를 나타내는 것이 아니라 문자열을 사용해야합니다. 예를 들어 제공 한 예제는 프로덕션 소프트웨어에서 허용되지 않습니다.

모든 언어에는 다양한 기본 데이터 유형이 있으므로 작업에 가장 적합한 언어를 사용해야합니다. 예제를 사용하기 위해 숫자 상수를 사용하여 다른 상태를 나타낼 수 있습니다. 왼쪽은 0의 값을 가질 수 있고 오른쪽은 1입니다. 언급 한 이유 외에도 숫자 값은 적은 공간 (메모리)을 차지하며 여러 문자열을 비교하는 것보다 숫자를 비교하는 것이 항상 빠릅니다.

제안 된대로 언어가 허용하는 경우 열거 형을 사용하십시오. 구체적인 예에서는 분명히 더 나은 선택입니다.


속도와 메모리는 중요하지 않습니다. 즉, 열거 형이나 상수를 선호합니다. 데이터가 XML과 같은 텍스트 형식에서 오는 경우 문자열이 더 의미가 있지만 모든 대문자 또는 모든 대문자와 일관성이 있습니다. 또는 항상을 변환하십시오 (예 : g). if (uppercase(foo) == "LEFT")
user949300

2
@ user949300 문자열을 모두 대문자 또는 소문자로 변환하는 것도 신뢰할 수 없습니다. 누군가가 터키 와 같은 다른 로케일을 방문하거나 사업을 확장하기로 결정하고 순진한 대문자 케이싱 (또는 로우 케이싱) 문자열 비교를 중단 할 가능성이 있습니다 .
8bittree

속도와 메모리에 대한 관심은 항상 좋은 습관이며 무한한 자원이 아닙니다. 가독성이나 다른 트레이드 오프를 위해 의식적으로 희생해도 괜찮지 만 여기에는 해당되지 않습니다. 그러나 걱정하지 않으면 응용 프로그램이 느리거나 낭비 될 수 있습니다.
Nagev

문자열 비교는 열거 형을 비교하는 것보다 50 배 느릴 수 있습니다. 대부분 중요하지 않습니다. 그러나 코드가 이미 느린 편이라면 그 차이로 인해 허용되지 않을 수 있습니다. 물론 더 중요한 것은 문자열을 사용하면 컴파일러가 철자 실수를 도울 수 없다는 사실입니다.
gnasher729

1

상황에 맞는 데이터 유형 만 사용하십시오.

사용량의 string기본이되는 인터 / 인트라 - 통신 애플리케이션과 같은 형태는 본질적으로 문제가되지 않는다. 사실, 때로는 문자열을 사용하는 것이 좋습니다. 퍼블릭 API가있는 경우 API에 들어오고 나가는 값을 사람이 읽을 수있는 것이 바람직 할 수 있습니다. API를 사용하는 사람들이 배우고 디버깅하기가 더 쉽습니다.

코드의 실제 문제 는 값 을 반복 하는 데 있습니다.

이 작업을 수행하지 마십시오 :

if (direction == 'left') {
  goLeft();
}

이러한 조건 중 하나에 오타가 있거나 다른 곳에서 "왼쪽"을 사용 하면 잘못 입력 했기 때문에 코드 기반 검색을 효과적으로 수행하지 못할 수 있습니다 .

대신, 사용하는 언어로 필요한 데이터 유형에 따라 열거 형 또는 상수에 대한 코드를 작성하십시오.

수단이 있음을 LEFT할당-에해야 한 번 하고 한 번만 응용 프로그램입니다. 그리고 나머지 코드는 이러한 열거 형 또는 상수를 활용해야합니다.

const string LEFT = "left";

if (direction == LEFT) {
  goLeft();
}

또한 원하는 경우 나중에 길 찾기에 사용하는 데이터 유형을보다 쉽게 ​​변경할 수 있습니다.


1

나쁜 습관입니까?

아마도 그렇습니다.하지만 정확히 당신이하고있는 것과 사용중인 프로그래밍 언어에 달려 있습니다.

귀하의 예에서, 방향이 취할 수있는 작고 고정 된 값 세트가 있다고 추론 할 수 있습니다. 이 경우 문자열을 사용할 때 이점이 없으며 몇 가지 확실한 단점이 있습니다. 이 예의 경우 :

  • enum프로그래밍 언어이 지원하는 경우 형태가 바람직 할 것이다.
  • 그렇지 않으면 명명 된 정수 상수가 사용되며 상수에 대한 단일 정의가 사용됩니다.

그러나 값 집합이 동적으로 수정 가능하거나 시간이 지남에 따라 진화해야하는 경우 에는 답 이 다를 수 있습니다 . 대부분의 언어에서 enum유형을 변경하면 (예 : 값 추가 또는 제거) 완전히 다시 컴파일해야합니다. 예를 들어 Java에서 열거 형 값을 제거하면 이진 호환성이 손상됩니다. 명명 된 정수 상수에도 동일하게 적용됩니다.

이와 같은 시나리오에서는 다른 솔루션이 필요할 수 있으며 문자열 사용이 옵션 중 하나입니다. 시나리오에 동적 확장이있는 고정 코어가 필요한 경우 문자열 리터럴과 명명 된 상수를 결합 할 수 있습니다.


Java로 구현하는 경우 character.direction == "left"다른 이유로 나쁜 습관이 있습니다. ==문자열 동등이 아닌 개체 ID를 테스트하기 때문에 문자열을 비교 하는 데 사용해서는 안됩니다 . ( "left"문자열 의 모든 인스턴스 가 인턴되었음을 보장 할 수 는 있지만 전체 응용 프로그램 분석이 필요합니다.)


1
고정 된 것처럼 보이는 것은 종종 그렇게 고정되지 않은 것으로 밝혀졌습니다. 예를 들어 4 방향은 8이 될 수 있습니다.
Jimmy T.

@JimmyT. -상황에 따라 다릅니다. 예를 들어, 게임에서 캐릭터가 4에서 8로 이동할 수있는 방향 수를 변경하면 게임 규칙을 완전히 점검하고 규칙을 구현하는 코드가 필요합니다. 사용 String방향을 나타내는 것은 가까운 일의 양 제로 차이로 만드는 변경을 포함한다. 보다 합리적인 접근 방식은 방향 수가 변경되지 않는다고 가정 하고 게임 규칙이 근본적으로 변경된 경우 어느 쪽이든 할 일이 많음을 인식하는 것입니다 .
Stephen C

@JimmyT-완전히 동의합니다. 이것이 여러 번 발생하는 것을 보았을 때 개발자가 문자열을 재정의하는 지름길을 단축하도록 예를 들어 product = "Option"이 product = "Option_or_Future"가되어 코드의 의미를 완전히 잃게됩니다.
Chris Milburn

-3

제안한대로 Enum을 사용해야합니다. 그러나 Strigns 대신 Enum을 사용하는 것만으로는 충분하지 않습니다. 당신의 특별한 예에서, 플레이어 속도는 실제로 물리학에 의한 벡터 여야합니다 :

class Vector {
  final double x;
  final double y;
}

그런 다음이 벡터를 사용하여 각 틱마다 플레이어 위치를 업데이트해야합니다.

그런 다음 가독성을 높이기 위해 이것을 열거 형과 결합 할 수 있습니다.

enum Direction {
  UP(new Vector(0, 1)),
  RIGHT(new Vector(1, 0)),
  DOWN(new Vector(0, -1)),
  LEFT(new Vector(-1, 0));

  private Vector direction;

  Direction(Vector v) {
    this.direction = v;
  }

  public Vector getVector() { return this.direction; }
}

4
-1 당신은 그가 제시 한 예에 너무 많이 들어가고 있습니다.
피터 B
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.