亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

證明迭代鍵的 `get` 非空

證明迭代鍵的 `get` 非空

慕尼黑5688855 2023-06-04 10:32:10
我有一個具有類似地圖功能的接口,但沒有實現 Java 的 Map 接口。地圖接口還實現了Iterable<Object>;它遍歷地圖的鍵我想this在增強循環的主體中使用(見下文),但沒有斷言,并用于get檢索迭代鍵的值,并且沒有[ERROR]來自 Checker Framework 的 an 。這完全有可能嗎?您能否提供從哪里開始的指示或可以學習的示例?我試著隨意地在這里和那里灑一些@KeyFors,但是由于缺乏完全理解我在做什么,我可能需要一段時間才能找到正確的位置;-)我知道我們可能會使用“條目迭代器”并避免首先解決這個問題,但我真的只是想學習如何向 Checker Framework 傳授鍵迭代器和方法之間的語義關系@Nullable get。這是一個最小的工作示例:import org.checkerframework.checker.nullness.qual.Nullable;interface IMap extends Iterable<Object> {    @Nullable Object get(Object o);    IMap put(Object key, Object value); // immutable put    IMap empty();    default IMap remove(Object key) {       IMap tmp = empty();       for (Object k : this) {           if (!k.equals(key)) {               tmp.put(k, get(k)); // get(k) is always non-null because of the key iterator           }       }       return tmp;    }}class Map implements IMap {   java.util.Map<Object, Object> contents = new java.util.HashMap<>();   public Map() { }   private Map(java.util.Map<Object, Object> contents) {      this.contents = contents;      }   @Override   public @Nullable Object get(Object key) {     return contents.get(key);   }   @Override   public IMap empty() {       return new Map();   }   @Override   public IMap put(Object key, Object value) {      java.util.Map<Object, Object> newContents = new java.util.HashMap<>();      newContents.putAll(contents);      newContents.put(key, value);      return new Map(newContents);   }   @Override   public java.util.Iterator<Object> iterator() {      return contents.keySet().iterator();   }}
查看完整描述

2 回答

?
紅糖糍粑

TA貢獻1815條經驗 獲得超6個贊

Nullness Checker 警告您規范(類型注釋)與代碼本身不一致。


無效性問題

您的代碼的關鍵問題在這里:


tmp.put(k, get(k))

錯誤信息是:


error: [argument.type.incompatible] incompatible types in argument.

? ? ? ? ? ? ? ?tmp.put(k, get(k)); // get(k) is always non-null because of the key iterator

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^

? found? ?: @Initialized @Nullable Object

? required: @Initialized @NonNull Object

以下是兩個不兼容的規范:

  1. put需要一個非空的第二個參數(回想一下這@NonNull是默認值):

???public?IMap?put(Object?key,?Object?value)?{?...?}
  1. get可能隨時返回 null,而客戶端無法知道返回值何時可能為非 null:

???@Nullable?Object?get(Object?o);

如果你想聲明一個方法的返回值在一般情況下是可以為空的,但在某些情況下是非空的,那么你需要使用條件后置條件,比如@EnsuresNonNullIf.

也就是說,Nullness Checker對Map.get.?您的代碼不使用它,因為您沒有覆蓋的方法java.util.Map.get(盡管它確實有一個名為的類Map,與 無關java.util.Map)。

如果您想要對 進行特殊情況處理IMap.get,則可以:

  • 你的課程應該擴展java.util.Map,或者

  • 您應該擴展 Nullness Checker 以識別您的班級。

地圖關鍵問題

你能提供從哪里開始的指導或可以學習的例子嗎?

我嘗試隨意地在這里和那里灑一些@KeyFors,但由于缺乏完全理解我在做什么,我可能需要一段時間才能找到正確的位置;-)

請不要那樣做!那就是痛苦。手冊告訴你不要那樣做;相反,首先思考并編寫描述代碼的規范。

@KeyFor以下是您可以編寫的三個注釋:

interface IMap extends Iterable<@KeyFor("this") Object> {

...

? ? default IMap remove(@KeyFor("this") Object key) {

...

? ? @SuppressWarnings("keyfor") // a key for `contents` is a key for this object

? ? public java.util.Iterator<@KeyFor("this") Object> iterator() {

這些注釋分別說明:

  1. 迭代器返回此對象的鍵。

  2. 客戶端必須為此對象傳遞一個密鑰。

  3. 迭代器返回此對象的鍵。我抑制了警告,因為此對象充當包含對象的包裝器,而且我不記得 Checker Framework 有一種方式說“此對象是一個字段的包裝器,它的每個方法都具有相同的屬性作為那個領域的方法。”

結果類型檢查沒有問題(此答案第一部分中指出的無效性除外):

import org.checkerframework.checker.nullness.qual.KeyFor;

import org.checkerframework.checker.nullness.qual.NonNull;

import org.checkerframework.checker.nullness.qual.Nullable;


interface IMap extends Iterable<@KeyFor("this") Object> {

? ? @Nullable Object get(Object o);

? ? IMap put(Object key, Object value); // immutable put

? ? IMap empty();


? ? default IMap remove(@KeyFor("this") Object key) {

? ? ? ? IMap tmp = empty();


? ? ? ? for (Object k : this) {

? ? ? ? ? ? if (!k.equals(key)) {

? ? ? ? ? ? ? ? tmp.put(k, get(k)); // get(k) is always non-null because of the key iterator

? ? ? ? ? ? }

? ? ? ? }


? ? ? ? return tmp;

? ? }

}


class Map implements IMap {

? ? java.util.Map<Object, Object> contents = new java.util.HashMap<>();


? ? public Map() {}


? ? private Map(java.util.Map<Object, Object> contents) {

? ? ? ? this.contents = contents;

? ? }


? ? @Override

? ? public @Nullable Object get(Object key) {

? ? ? ? return contents.get(key);

? ? }


? ? @Override

? ? public IMap empty() {

? ? ? ? return new Map();

? ? }


? ? @Override

? ? public IMap put(Object key, Object value) {

? ? ? ? java.util.Map<Object, Object> newContents = new java.util.HashMap<>();

? ? ? ? newContents.putAll(contents);

? ? ? ? newContents.put(key, value);

? ? ? ? return new Map(newContents);

? ? }


? ? @Override

? ? @SuppressWarnings("keyfor") // a key for `contents` is a key for this object

? ? public java.util.Iterator<@KeyFor("this") Object> iterator() {

? ? ? ? return contents.keySet().iterator();

? ? }

}


查看完整回答
反對 回復 2023-06-04
?
偶然的你

TA貢獻1841條經驗 獲得超3個贊

總結信息性接受的答案:

  1. 無法對給定的代碼示例進行注解,使得迭代器和 IMap 的 get 方法之間的語義關系可以指定給 Checker Framework;

  2. 因此,當前報告的錯誤需要本地非空斷言,重寫代碼以避免鍵迭代器或 SuppressWarning 注釋。

  3. 如果我們想避免這些變通方法,那么有必要對檢查器框架進行擴展,例如它是如何針對 java.util.Map 進行特殊處理的。


查看完整回答
反對 回復 2023-06-04
  • 2 回答
  • 0 關注
  • 193 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號