Rustで一行が100文字以上になるとフォーマットできなくなる

100字以上の文字列を扱う場合、その行orファイル全体がフォーマットができなくなる時がある。

また、vscodeやIDEAでは書いてる時に怒られないし、ビルドしてもエラーになるわけではないので全然気付けなかった…

※この記事は明確な根拠はなく推測である部分があります。

結論

直接的な原因は見つけられなかった…

推測だが、rustのガイドラインでは一行の文字数を99文字以下にするように推奨しているらしいので、100文字以上にすると想定外な挙動になってしまうこともあるのかもしれない。99文字以下を心がけよう!

環境

❯ cargo -V
cargo 1.59.0 (49d8809dc 2022-02-10)

❯ rustc --version            
rustc 1.59.0 (9d1b2106e 2022-02-23)

❯ rustup component list | grep "(installed)"
cargo-aarch64-apple-darwin (installed)
clippy-aarch64-apple-darwin (installed)
rls-aarch64-apple-darwin (installed)
rust-analysis-aarch64-apple-darwin (installed)
rust-src (installed)
rust-std-aarch64-apple-darwin (installed)
rustc-aarch64-apple-darwin (installed)
rustfmt-aarch64-apple-darwin (installed)

確認してみたこと

以下のように引数内の行ではインデント含め100文字未満で記述する必要があるようだ。ただし、コメントやカンマや丸括弧はカウントされてなさそう…

// これより長い文字列を引数内で扱うと、この行だけorファイル全体がフォーマットができなくなる
assert_eq!(
    "678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", // 99文字(インデントとダブルクォーテーション含める, `,`を除く)
    "678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678" // 99文字
);

// インデントが増えても同様
fn main() {
    assert_eq!(
        "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", // 99文字(インデントとダブルクォーテーション含める, `,`を除く)
        "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678" // 99文字
    );
    let s =
        "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678";
}

fn hellooooo12345678901234567890123456789012345678901234567890123456789012345678901234567890123456(
) -> i32 {
    5
}
// これより長い関数名を引数内で扱うとファイル全体でフォーマットができなくなる
assert_eq!(
    5,
    helloooooo1234567890123456789012345678901234567890123456789012345678901234567890123456789012345( // `(`を除いて99文字
    )
);

また、以下のように100行越えを一行で書く分には、ファイル全体がフォーマットできなくなるわけではないが、

assert_eq!("test", "6789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")
let s = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"

以下のように謎に空白を作ってしまっても、この行だけはフォーマットできない

assert_eq!(    "test"    , "6789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")
let      s        =                              "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";

調べたこと

残念ながら直接的な原因は見つけられなかった…。

推測だがrustのガイドラインでは一行の文字数を99文字以下にするように推奨しているらしいので、100文字以上にすると想定外な挙動になってしまうこともあるのだろうか…

ちなみに100文字ではなく99文字というのは、pep8の79文字推奨と同様の理由らしい。以下参考

以下、pep8の引用

ほとんどのツールのデフォルトの折り返し動作は、コードの見た目の構造を壊し、理解するのを難しくします。79文字という制限は、ウィンドウの幅を80に制限し、行を折り返すときにツールが行末にマーカーを置いたとしても、エディタに折り返す動作をさせない目的で選ばれています。

引用: はじめに — pep8-ja 1.0 ドキュメント (参照: 2022/4/6)

また、rustのガイドラインについて、こちらのPRまでは「一行は80文字以下にすべきで、100文字以下は必須」ということだった。というのもあり、100文字に対する折り返しを考慮すると99文字ということらしい。

rustのガイドラインのPR: Decrease line lengths by one by chris-morgan · Pull Request #12 · rust-lang/rust-guidelines

Vue2系とTypescript周りの個人的な実装方針と所感

個人開発やプロダクト初期のVue 2系とTypescriptを用いたSPAの開発で得た知見のメモ。まだ試行錯誤中。

  • 注意
    • 適宜更新します。もし気になる点ございましたらご指摘いただけますとうれしいです。
    • 自分が所属している団体を代表するような意見ではございません。
    • 現在執筆中

小ネタ

リアクティブな連想配列

Vue 2系ではオブジェクトのプロパティを更新してもDOMが更新されずに困ることがある。 以下は、オブジェクトの参照自体がリアクティブなVueインスタンスのプロパティの場合、オブジェクトの任意のプロパティを更新した時に、オブジェクトの参照も都度変更してしまえばDOMの更新がされるだろうというやり方。オブジェクトのプロパティが多ければ処理効率は悪そう…

  data(): {
    return {
      hashMap: Vue.observable<MyHashMap>(new MyHashMap({})
    }
  },
class Xxx {
  constructor(public aId: number, public bId: number | undefined) {}
}

// aIdとbId毎のXxxを保持するコレクションオブジェクト
// TODO: ジェネリクス使って再実装
class MyHashMap {
  // key: `${aId},${bId}`
  constructor(private state: { [key in string]: Xxx }) {}

  get = (aId: number, bId: number | undefined): Xxx | undefined => {
    const key = MyHashMap.createKeyBy(aId, bId)
    return this.state[key]
  }

  values = (): Xxx[] => Object.values(this.state)

  valuesBy = (aId: number, bId: number): Xxx[] => {
    return Object.values(this.state).filter(
      xxx =>
        xxx.aId === aId &&
        (xxx.bId || undefined) === bId
    )
  }

  has = (aId: number, bId: number): boolean => {
    return this.get(aId, bId) != undefined
  }

  set = (aId: number, bId: number | undefined, xxx: Xxx): void => {
    // NOTE: リアクティブにするために新しくオブジェクトを生成して代入する.
    const newState = { ...this.state }
    const key = MyHashMap.createKeyBy(aId, bId)

    newState[key] = xxx
    this.state = newState
  }

  replace = (before: Xxx, after: Xxx): void => {
    this.set(before.aId, before.bId, after)
  }

  // NOTE: このクラスのstateのkeyを生成する時は必ずこのメソッドを使うようにする.
  static createKeyBy = (aId: number, bId: number | undefined): string => {
    return `${aId},${bId}`
  }

  // NOTE: このクラスのstateのkeyからkeyの構成要素を取得したい時は必ずこのメソッドを使うようにする.
  // return [aId, bId]
  static fromKey = (key: string): [number, number | undefined] => {
    const maybeIds = key.split(',')
    if (maybeIds.length === 3) {
      return [Number(maybeIds[0]), maybeIds[1] == 'undefined' ? undefined : Number(maybeIds[1])]
    }
    console.log(`Error in MyHashMap#fromKey: ${maybeIds}`)
    return [NaN, NaN]
  }
}

コンポーネントへのメソッドの渡し方は$emitよりもpropを使う

  • 理由
    • $emitは文字列でメソッド名を扱ったり、引数が可変長で型がAnyだったりで型安全ではないため
    • propであれば型安全に扱えるため

↓以下、子コンポーネント側の例

  props: {
    inputFunc: {
      type: Function as PropType<(value: string) => void>,
      required: true,
    },
  }

vuexよりはstoreパターンをなるべく使う

  • vue.observableを使ったシンプルなstoreパターンを採用する
    • オブジェクトをリアクティブにするため(storeの値が変わったとき、変更をDOMにも反映させるようにするため)
    • シンプルなstoreパターンで事足りるため。

今のところvuexはあまり利用していない。vuexを利用していない理由としては - そもそも小さなプロダクトには、vuexがは向いていないから - 型安全ではないから(型安全にしようとすると、デコレータをたくさん使う…)

nullよりもundefinedをなるべく使う

  • 理由
    • Optional Chainingではnullではなくundefinedを扱うため

扱うUIフレームワークに合わせるのもいいかもしれない。Vuetifyではnullよりもundefinedを扱っているケースが多く見受けられる

axiosに渡すAPIのリクエストやレスポンスを表すオブジェクトの定義はclassかinterfaceか

classを定義すれば同名のinterfaceも定義したようなものなので、インスタンス化してなくてもメソッドが使えないだけでプロパティは参照できる。 そのため、axiosで受け取る・axiosで渡すオブジェクトの定義はclassかinterfacelかの選択肢がある。

  • class
    • 利点
      • 表示で使うクラスを再定義する必要がなくなる場合がある
      • getterやメソッドを定義することで、表示ロジックやビジネスロジックを表現できる
    • 欠点
      • メソッドを使いたいならインスタンス化は必須であり、単なるオブジェクトからクラスのインスタンスへ変換する必要が出てきてしまう
  • interface
    • 利点
    • 欠点
      • 手続っぽい書き方になりがち
      • さらにクラスに変換するようなことになるので冗長になりがち。実装コストが高くなる

所感

  • 型安全はありがたい。
    • 関数の引数に違う型のものを渡そうとするとエラーになってくれるので嬉しい
    • 仕様変更でとあるフィールドを修正するとき、安心して修正できる。型を修正すれば、その型のフィールドを使ったものはほとんどエラーになるので、修正漏れしにくい。
    • もし型定義がなかったらオブジェクトにはどんなフィールドがあるか覚えてないといけない or 仕様ページ(wiki等)を見に行く手間があるので、ストレスフルだと推測できる。
  • ライブラリに型定義ファイルがないときは、自分で作る必要があるので面倒

m1 macで原神するために1台に11.2.3と最新の2つのバージョンを両方インストールした

概要

m1 macでいくつかのiosアプリがインストールでき、そのうち「原神」もできていたのですが、macOS 11.3にアップデートしたところできなくなったのでそのメモ

※2022年2月 追記

旧タイトル: m1 macで原神をするならOSアップデートは11.2.3まで説【2021年5月現在】

旧タイトルは語弊がありそうなので変更しました。

対象読者

※この記事は多くの方に役立ちません。自分用のメモとして残してあります。

結論

  • 一台のm1 macmacOS 11.2.3と最新のmacOSをインストールしておく
    • macOS 11.2.3で引き続き原神を楽しむ
    • 普段使いや仕事では最新のmacOSを利用する
  • PlayCoverやNoxPlayerは使わない
  • macOS 11.2.3のインストーラーはもう配布していなそうなので要注意

所感

  • PlayCoverやNoxPlayerはシステム整合性保護を一時的にでも無効にするのでリスキーかなっと思ったのと、原神のログイン認証のたびにシステム整合性保護を無効にするのは面倒かなと思い避けました。
  • Appleサポート公式に紹介されてはいますが、デュアルブートはPC的にはやや不安定な印象があるので、OS切り替えまくってPCがお釈迦にならないか若干心配ではあります。
  • 別のバージョンのOSに切り替えるためには再起動が必要なため煩雑です。原神のプレイ頻度は減ってしまいました…。
  • Time MachineでバックアップしておけばOSのバージョンも復元できる的な記事をよく見かけますが、実際に試したことないので自信ありません。
  • 上記のような懸念や煩雑さがあるくらいならiPad買って原神した方が幸せかもしれない。

↓別のバージョンのOSをインストールする際の参考

個別の APFS ボリュームに macOS をインストールする - Apple サポート (日本)


以下、2021年5月に書いたもの

前提

  • iMobile M1 App Checker経由で原神をインストールした
  • macOS 11.2.3までは正常に原神が遊べた
  • macOS 11.3では原神が遊べなかった

過去のmacOSインストーラーの入手

アップデートして既存のアプリが使えなくなったのなら、元に戻せばまた使える!ということで過去のmacOSのバージョンを入手します。

↓以下のサイトにありました。以下のサイトでは他にも過去のバージョンのmacOSの変更点やインストーラーのリンクを掲載してくれているので重宝しそうです。 macOS Big Sur 11.2.3 Update (20D91) is Live! What’s New?

macOS 11.2.3のインストーラーのリンク。ドメインappleのものなので信用して使ってます。 http://swcdn.apple.com/content/downloads/12/32/071-14766-A_Q2H6ELXGVG/zx8saim8tei7fezrmvu4vuab80m0e8a5ll/InstallAssistant.pkg

その他メモ

↓記事投稿現在、iosアプリの原神はm1 macと互換性がないっぽいらしい… 完全無料!Mac/iPhoneアプリと M1 Macの互換性をチェック|iMobie

懸念点

OSのアップデートをしないということはセキュリティ的にリスクがあるので、あまり嬉しくはないのですが、それでもm1 macで原神を遊びたいのでしばらくはアップデートには慎重になると思います…。自己責任で…。

macOS Big Sur 11.3.1 のセキュリティコンテンツについて - Apple サポート