5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「?」演算子まとめ(TypeScript,C#,Dart,Rust,Python)

Last updated at Posted at 2024-06-12

記号?は、プログラミング言語ごとに多様な役割で使われます。
複数の言語を扱っていると混乱するので、表にまとめました。
表題の通り、本記事では、TypeScript, C#, Dart, Rust, Pythonについて記載します。

役割 プログラミング言語
三項演算子(? :) TypeScript, C#, Dart let isAdult = age >= 18 ? "Yes" : "No"; (TypeScript)
(Rust, Python) let is_adult = if age >= 18 { "Yes" } else { "No" }; (Rust)
オプショナルチェイニング(null条件演算子)(.?) TypeScript, C#, Dart let user1Name = user1?.name; (TypeScript)
(Rust, Python) user1_name = getattr(user1, 'name', None) (Python)
null合体演算子(??) TypeScript, C#, Dart let name = userName ?? "Guest"; (TypeScript)
(Rust, Python) let default_name = name.unwrap_or_else(|| "Guest".to_string()); (Rust)
エラー・None委譲(?) Rust let content = std::fs::read_to_string(file_path)?;

各役割の説明

三項演算子

TypeScript

let age = 18;
let isAdult = age >= 18 ? "Yes" : "No";
console.log(isAdult); // Output: Yes

C#

int age = 18;
string isAdult = age >= 18 ? "Yes" : "No";
Console.WriteLine(isAdult); // Output: Yes

Dart

int age = 18;
String isAdult = age >= 18 ? "Yes" : "No";
print(isAdult); // Output: Yes

(Rust)

Rustには直接の三項演算子はありませんが、if式を使って同じことができます。

let age = 18;
let is_adult = if age >= 18 { "Yes" } else { "No" };
println!("{}", is_adult); // Output: Yes

(Python)

Pythonには三項演算子はありませんが、条件式を使って同じことができます。

age = 18
is_adult = "Yes" if age >= 18 else "No"
print(is_adult) # Output: Yes

オプショナルチェイニング(null条件演算子)

オプショナルチェイニング演算子?.は、オブジェクトのプロパティやメソッドにアクセスする際に、オブジェクトの存在(null値やundefined値)チェックを行い、存在しなければnullundefinedを返します。

TypeScript

let user1 = {
    name: "Alice"
};
let user2 = undefined
let user1Name = user1?.name; // "Alice"
let user2Name = user2?.name; // undefined

C#

C#では、?.はnull条件演算子と呼ばれますが、他のオプショナルチェイニングと同様です。

class User
{
    public string Name { get; set; }
}

class Program
{
    static void Main()
    {
        User user1 = new User { Name = "Alice" };
        User user2 = null;

        string user1Name = user1?.Name; // "Alice"
        string user2Name = user2?.Name; // null
    }
}

Dart

class User {
  String? name;

  User(this.name);
}

void main() {
  var user1 = User("Alice");
  User? user2;

  String? user1Name = user1.name; // "Alice"
  String? user2Name = user2?.name; // null
}

(Rust)

Rustにはオプショナルチェイニング演算子の直接的なサポートはありません。
Option型とand_then関数を使用して同様の機能を実現できます。

fn main() {
    struct User {
        name: Option<String>,
    }

    let user1: Option<User> = Some(User {
        name: Some("Alice".to_string()),
    });
    let user2: Option<User> = None;

    let user1_name = user1.as_ref().and_then(|u| u.name.as_deref()); // Some("Alice")
    let user2_name = user2.as_ref().and_then(|u| u.name.as_deref()); // None
}

(Python)

Pythonにはオプショナルチェイニング演算子の直接的なサポートはありません。
getattr関数を使って同様の機能を実現できます。

class User:
    def __init__(self, name=None):
        self.name = name

user1 = User(name="Alice")
user2 = None

user1_name = getattr(user1, 'name', None)  # "Alice"
user2_name = getattr(user2, 'name', None)  # None

null合体演算子

null合体演算子??は、nullundefinedの可能性がある値に対して、デフォルト値を設定します。

TypeScript

let name = null;
let defaultName = name ?? "Guest"; // "Guest"(nameがnullなので)

C#

string name = null;
string defaultName = name ?? "Guest"; // "Guest"(nameがnullなので)

Dart

String? name = null;
String defaultName = name ?? "Guest"; // "Guest"(nameがnullなので)

Rust

Rustではnull合体演算子が直接サポートされていません。
Option型とunwrap_or_else関数を使って、同等の機能を実現できます。

let name: Option<String> = None;
let default_name = name.unwrap_or_else(|| "Guest".to_string()); // "Guest"(nameがNoneなので)

Python

Pythonではnull合体演算子が直接サポートされていません。
or演算子で同等の機能を実現できます。

name = None
default_name = name or "Guest"  # "Guest"(nameがNoneなので)

いただいたコメントより追記

or演算子は、None以外のFalsyな値(空文字列 '', 空リスト [], 0, False など)に対してもデフォルト値を設定する点で、null合体演算子??とは挙動が異なるため、注意が必要です。

Pythonの場合

name = ""
default_name = name or "Guest"  # "Guest"

TypeScriptの場合

let name = "";
let defaultName = name ?? "Guest"; // ""

エラー・None委譲

Rust

Rustの?演算子は、Result<T, E>型のエラーやOption<T>型のNoneを、関数の呼び出し元に委譲します。

Result型の使用例

fn read_file(file_path: &str) -> Result<String, std::io::Error> {
    let content = std::fs::read_to_string(file_path)?;
    Ok(content)
}

std::fs::read_to_string関数がResult<String, std::io::Error>を返します。?演算子を使うことで、エラーが発生した場合は即座にread_file関数の呼び出し元へエラーを返します。

Option型の使用例

fn get_length(s: Option<&str>) -> Option<usize> {
    let s = s?;
    Some(s.len())
}

Option型の変数s?演算子を使うことで、値がNoneの場合は即座にget_length関数の呼び出し元へNoneを返します。

5
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?