【ABAP】ABAP7.4から導入された構文

## はじめに
ABAP7.4で、ABAPに色々な革新がもたらされました。
ABAP7.4は2013年にリリースされており新しいものではありませんが、私はこれまでに見たことや使ったことがありませんでした。
この記事では、筆者の独断で「便利だ」「使ってみたい」と感じた機能について紹介します。
ABAP7.4でリリースされた機能についての詳細は、末尾にあるリンクを参考にしてください。

## ABAP7.4で何が良くなったのか
・変数の宣言が楽になった
・中間変数を減らせるので、コードを短くできる

## 紹介する機能

1. 変数宣言
2. 内部テーブルの操作
    3. 内部テーブルの宣言
    4. 内部テーブルの読み込み
    5. 内部テーブルへの値の設定
    6. 特定の行のインデックスを取得する(line_index)
    7. 指定した行が存在するかどうかを確認する(line_exists)
8. 型変換
9. 文字列操作

## 1. 変数宣言
### 変数の定義
＜ABAP7.4より前＞
・変数はプログラムやルーチンの先頭でまとめて定義する
・宣言時に型の定義が必要

```abap
DATA l_str type string.
l_str = 'hello'.
```

＜ABAP7.4以降＞
・変数は使いたい場所で宣言すればよい
・コンパイラが型を判断してくれる

```abap
DATA(l_str) = 'hello'.
```
### メソッド呼び出し時の引数
メソッドから受け取る引数も、DATAを使用してその場で定義できます。
一方、汎用モジュールではDATAを利用した引数の定義はできませんでした。残念！

```abap
CALL METHOD cl_reca_date=>get_current_date
  EXPORTING
    id_timezone  = sy-zonlo
  IMPORTING
    ed_time      = DATA(l_time)
    ed_date      = DATA(l_date)
    ed_timestamp = DATA(l_timestamp)
    .
```
## 2. 内部テーブルの操作
### 内部テーブルの宣言
内部テーブルはDBを読み込むのに使うことが多いと思います。DATA宣言を使うと、SELECTで指定した項目を持つ内部テーブルを自動的に作ることができます。

```abap
DATA(l_mtart) = 'ROH'.
SELECT matnr, mtart FROM mara INTO TABLE @DATA(itab_mara) WHERE mtart = @l_mtart.
```
※SQL内で変数を使う場合は先頭に@をつけます。（データ定義か否かにかかわらず）


### 内部テーブルの読み込み
#### ワークエリアの作成
内部テーブルをループしてワークエリアに読み込むとき、内部テーブルの型を参照して自動的にワークエリアを作ることができます。

```abap
LOOP AT itab_mara INTO DATA(wa_mara).
  WRITE: / wa_mara-matnr, wa-mtart.
ENDLOOP.
```
フィールドシンボルも使えます。

```abap
LOOP AT itab ASSIGNING FIELD-SYMBOL(<fs_mara>).
  WRITE: / <fs_mara>-matnr, <fs_mara>-mtart.
ENDLOOP.
```
#### 指定した行を読み込む方法
＜ABAP7.4より前＞
・内部テーブルを読み込む際はインデックス、またはキーを指定してワークエリアに行を格納する

```abap
DATA: wa_mara LIKE LINE OF itab_mara.
READ TABLE itab_mara INTO w_mara INDEX 1.
READ TABLE itab_mara INTO w_mara WITH KEY matnr = 'BRICK002'.
```

＜ABAP7.4以降＞
・インデックスやキーを指定して直接行にアクセスできる

```abap
" インデックスを指定
wa_mara = itab_mara[ 1 ].
" キーを指定
wa_mara = itab_mara[ matnr = 'BRICK002' ].
```
データが読み込めない場合、例外CX_SY_ITAB_LINE_NOT_FOUNDが発生します。
ABAP7.4 SP8からは、例外が発生しないようにOPTIONALまたはDEFAULTを指定できるようになりました（VALUE #と組み合わせること）。
OPTIONALを指定した場合は、READ TABLEで対象の行がなかった場合と同じように初期値が返されます。

```abap
wa_mara = VALUE #( itab_mara[ matnr = 'BRICK002b' ] OPTIONAL ).
```
### 内部テーブルへの値の設定
#### 直接値を設定する
＜ABAP7.4より前＞
・ワークエリアで値を編集し、それを内部テーブルに格納する

```abap
DATA: lr_sel_mara TYPE RANGE OF mtart,
      wa_sel_mara LIKE LINE OF lr_sel_mara.

wa_sel_mara-sign = 'I'.
wa_sel_mara-option = 'EQ'.
wa_sel_mara-low = 'ROH'.
APPEND wa_sel_mara TO lr_sel_mara.
wa_sel_mara-low = 'HAWA'.
APPEND wa_sel_mara TO lr_sel_mara.
```

＜ABAP7.4以降＞
・VALUEを使って内部テーブルに値を直接入れることができる

構文その1: `VALUE <型> ((行データ1) (行データ2)...)`
型を明示的に指定する方法です。

```abap
TYPES: t_sel_mara TYPE RANGE OF mtart.
DATA(lr_sel_mara2) = VALUE t_sel_mara(
    ( sign = 'I' option = 'EQ' low = 'ROH')
    ( sign = 'I' option = 'EQ' low = 'HAWA')
 ).
```
構文その2: `VALUE # ((行データ1) (行データ2)...)`
テーブルの型が設定先の変数から推測できる場合はこちらの構文が使えます。

```abap
DATA: lr_sel_mara3 TYPE RANGE OF mtart.
lr_sel_mara3 = VALUE #(
    ( sign = 'I' option = 'EQ' low = 'ROH')
    ( sign = 'I' option = 'EQ' low = 'HAWA')    
 ).
```
sign, optionが共通の場合、次のような書き方もできます。

```abap
lr_sel_mara3 = VALUE #(
    sign = 'I' option = 'EQ' ( low = 'ROH') ( low = 'HAWA') 
 ).
```

### 特定の行のインデックスを取得する(line_index)
＜ABAP7.4より前＞
・READ TABLEなどで行を読み込み、sy-tabixを取得する

```abap
DATA: l_index type sy-tabix.

READ TABLE itab_mara TRANSPORTING NO FIELDS with key matnr = 'BRICK002'.
l_index = sy-tabix.
```

＜ABAP7.4以降＞
・line_index命令でインデックスを取得できる

```abap
l_index = line_index( itab_mara[ matnr = 'BRICK002' ] ).
```

### 指定した行が存在するかどうかを確認する(line_exists)
＜ABAP7.4より前＞
・READ TABLEして、sy-subrcの値で判断する

```abap
READ TABLE itab_mara TRANSPORTING NO FIELDS WITH KEY matnr = 'BRICK002'.
IF sy-subrc = 0.
  "存在する場合の処理
ELSE.
  "存在しない場合の処理
ENDIF.
```
＜ABAP7.4以降＞
・line_exists命令で判断できる

line_existsはブール値を返します。
ABAP7.4から、IF条件の結果がtureのときは `if <変数> = abap_true`という風にabap_trueを書かなくてもよくなったので、以下のような簡潔な書き方ができます。

```abap
IF line_exists( itab_mara[ matnr = 'BRICK002' ] ).
  "存在する場合の処理
ELSE.
  "存在しない場合の処理
ENDIF.
```

## 3. 型変換
サブルーチンで受け取った引数を汎用モジュールに渡すとき、汎用モジュールの型に合わせるために中間変数を定義したことはないでしょうか？

＜ABAP7.4より前＞
・中間変数に引数を格納して型変換し、汎用モジュール等に渡す

```abap
DATA: im_text(50) TYPE c,
      l_str       TYPE string, "中間変数
      l_xstr      TYPE xstring.

im_text = 'Hello'.
l_str = im_text.

CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
  EXPORTING
    text     = l_str
  IMPORTING
    buffer   = l_xstr
  .
```

＜ABAP7.4以降＞
・CONV命令で直接型を変換できる
・VALUEと同じく、型を明示的に指定する方法と#で暗黙的に指定する方法がある

```abap
CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
  EXPORTING
    text     = CONV string( im_text ) "明示的に型を指定
  IMPORTING
    buffer   = l_xstr
  .
```

## 4. 文字列操作
### 文字列結合
＜ABAP7.4より前＞
・CONCATENATEで文字列を結合
・結合する文字列の中にクォーテーション(')を使いたい場合、エスケープする必要がある

```abap
DATA: im_comment(10) TYPE c,
      l_out TYPE string.

im_comment = 'Hello!'.
CONCATENATE 'He said' '''' im_comment '''' INTO l_out SEPARATED BY space.
```

＜ABAP7.4以降＞
・`||`で囲った中にリテラルや変数を直接書き込むことができる
・変数は`{}`で囲む

```abap
l_out = |He said '{ im_comment }'|.
l_out2 = |Date: { sy-datum } Time: { sy-uzeit }|.
```

### Alpha変換
Alpha変換とは、内部書式（前ゼロつき）と外部書式（前ゼロなし）の変換のことです。

＜ABAP7.4より前＞
・汎用モジュール'CONVERSION_EXIT_ALPHA_INPUT'/'CONVERSION_EXIT_ALPHA_OUTPUT'を使って変換する

```abap
DATA: lv_input TYPE ebeln.
DATA: lv_output TYPE ebeln.

lv_input = 12345.

CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
  EXPORTING
    input  = lv_input
  IMPORTING
    output = lv_output. "0000012345
```

＜ABAP7.4以降＞
・`|{ <変数>  ALPHA = IN / OUT }|`で変換できる

```abap
DATA: lv_input TYPE ebeln.
DATA: lv_output TYPE ebeln.

lv_input = 12345.
lv_output =  |{ lv_input alpha = IN }|. "0000012345
```

## おわりに
ここで紹介した以外にも、ABAP7.4で登場した構文は色々あります。以下のブログがよくまとまっていておすすめなので興味のある方は読んでみてください。
[ABAP 7.40 Quick Reference](https://blogs.sap.com/2015/10/25/abap-740-quick-reference/)

## 参考
[ABAP News for Release 7.40 – What is ABAP 7.40?]
(https://blogs.sap.com/2013/05/22/abap-news-for-release-740-2/)
[ABAP News for 7.40, SP08 – More for Internal Tables](https://blogs.sap.com/2014/10/06/abap-news-for-740-sp08-more-for-internal-tables/)
[ABAP to the Future](https://www.sap-press.com/abap-to-the-future_4751/)
[ABAP 7.40 Quick Reference](https://blogs.sap.com/2015/10/25/abap-740-quick-reference/)