我目前正在嘗試提高我的顫振??應用程式中的 null 安全性,但是在處理 null 安全性方面的實際經驗相對較少,我對自己的一些決定沒有信心。
例如,我的應用程式需要用戶登錄,因此我有一個Auth
保留身份驗證狀態的類。
class Auth {
final String? token;
final User? user;
Auth(this.token, this.user);
}
在我的應用程式中,我確保user
只有在用戶登錄時才能訪問該屬性,因此可以安全地執行以下操作:
final auth = Auth(some_token, some_user);
// and when I need to access the user
final user = auth.user!
這導致了第一個問題:
是否建議在應用程式的許多地方使用空斷言運算子?
我個人覺得在整個應用程式中做類似的事情有點不舒服auth.user!.id
,所以我目前是這樣處理的:
class Auth {
final User? _user;
Auth(this._token, this._user);
User get user {
if (_user == null) {
throw StateError('Invalid user access');
} else {
return _user!;
}
}
}
但我不確定這是否是零安全的推薦做法。
對于下一個問題,我有一個處理 API 呼叫的類:
class ApiCaller {
final String token;
ApiCaller(this.token);
Future<Data> getDataFromBackend() async {
// some code that requires the token
}
}
// and is accessed through riverpod provider
final apiCallerProvider = Provider<ApiCaller>((ref) {
final auth = ref.watch(authProvider);
return ApiCaller(auth.token);
})
My ApiCaller
is accessed through providers and thus the object is created when the App starts. Obviously, it requires token
to be available and thus depends on Auth
. However, token
could also be null
when the app starts and the user is not logged in.
Since I'm confident that apiCaller
isn't used when there is no existing user, doing this:
class ApiCaller {
// make token nullable
final String? token;
ApiCaller(this.token);
Future<Data> getDataFromBackend() async {
// some code that requires the token
// and use token! in all methods that need it
}
}
final apiCallerProvider = Provider<ApiCaller>((ref) {
final auth = ref.watch(authProvider);
if (auth.token == null) {
return ApiCaller()
} else {
return ApiCaller(auth.token);
}
})
should be fine. However, this also makes me use a lot of token!
throughout all methods, and I'm not too sure about that.
I could also simply do ApiCaller('')
in the non-null token
version, but this seems more of a workaround than a good practice.
對不起,冗長的問題。我嘗試尋找一些關于空安全的實際實踐的更好的文章,但大多數只是語言基礎,所以我希望你們中的一些人能給我一些見解。提前致謝!
uj5u.com熱心網友回復:
當您知道可空變數不為空時,避免使用的最簡單方法!
是像在第一個問題上所做的那樣制作一個非空 getter:
User get user {
if (_user == null) {
throw StateError('Invalid user access');
} else {
return _user!;
}
}
我會讓你知道在拋出錯誤之前不需要檢查值是否為空,空檢查運算子正是這樣做的:
Uset get user => _user!;
當然,除非您非常關心錯誤本身并想拋出不同的錯誤。
至于你的第二個問題,這個問題有點棘手,你知道在初始化之前你不會訪問變數,但是你必須在它有值之前對其進行初始化,因此你唯一的選擇是讓它為空,我個人不喜歡使用late
關鍵字,但它是專門為此目的而構建的,因此您可以使用它。遲到的變數在明確分配之前不會有值,否則會拋出錯誤,另一種解決方案是在其他頁面上制作非空 getter。
此外,您不需要在這里進行空檢查,因為結果是相同的:
if (auth.token == null) {
return ApiCaller()
} else {
return ApiCaller(auth.token);
}
而是這樣做:
return ApiCaller(auth.token);
這對我來說確實是一個簡單的問題,你只是不習慣使用 null-safety,這意味著對你來說,!
看起來丑陋或不安全,但你使用它的次數越多,你就會越適應它即使你在你的應用程式中大量使用它,它看起來也不會是糟糕的代碼。
Hopefylly,我的回答對你有幫助
uj5u.com熱心網友回復:
是否建議在應用程式的許多地方使用空斷言運算子?
我認為空斷言運算子有點代碼味道,并盡可能避免使用它。在許多情況下,可以通過使用區域變數、檢查null
并允許發生型別提升或使用可識別空值的運算子來優雅地失敗來避免這種情況。
在某些情況下,使用 null 斷言更簡單、更清晰,只要您能在邏輯上保證該值不會是null
. 如果您對應用程式因失敗的空斷言而崩潰感到滿意,因為這在邏輯上應該是不可能的,那么使用它是完全可以的。
我個人覺得在整個應用程式中做類似的事情有點不舒服
auth.user!.id
,所以我目前是這樣處理的:class Auth { final User? _user; Auth(this._token, this._user); User get user { if (_user == null) { throw StateError('Invalid user access'); } else { return _user!; } } }
但我不確定這是否是零安全的推薦做法。
除非你想控制錯誤,否則拋出StateError
是沒有意義的。TypeError
無論如何,null 斷言運算子都會拋出錯誤 (a )。
user
我個人認為吸氣劑沒有多大價值。您仍然會在任何地方使用 null 斷言運算子,但它只是隱藏在方法呼叫后面。它會使代碼更漂亮,但不太清楚潛在的故障點在哪里。
如果你發現自己在一個函式中多次對同一個變數使用 null 斷言運算子,你仍然可以使用區域變數來使它更好:
void printUserDetails(Auth auth) {
final user = auth.user;
user!;
// `user` is now automatically promoted to a non-nullable `User`.
print(user.id);
print(user.name);
print(user.emailAddress);
}
I think ultimately you need to decide what you want your public API to be and what its contracts are. For example, if a user is not logged in, does it make sense to have an Auth
object at all? Could you instead have make Auth
use non-nullable members, and have consumers use Auth?
instead of Auth
where null
means "not logged in"? While that would be passing the buck to the callers, making them check for null
everywhere instead, they're already responsible to not do anything that accesses Auth.user
when not logged in.
Another API consideration is what you want the failure mode to be. Does your API contract stipulate in clear documentation that callers must never access Auth.user
when not logged in? If the caller is in doubt, are they able to check themselves? If so, then making accesses to Auth.user
fatal when it's null
is reasonable: the caller violated the contract due to a logical error that should be corrected.
However, in some situations maybe that's too harsh. Maybe your operation can fail at runtime for other reasons anyway. In those cases, you could consider failing gracefully, such as by returning null
or some error code to the caller.
final apiCallerProvider = Provider<ApiCaller>((ref) { final auth = ref.watch(authProvider); if (auth.token == null) { return ApiCaller() } else { return ApiCaller(auth.token); } }
Your ApiCaller
class as presented does not have a zero-argument constructor, so that doesn't make sense. If you meant for its constructor to be:
final String? token;
ApiCaller([this.token]);
then there's no difference between ApiCaller()
and ApiCaller(null)
, so you might as well just unconditionally use ApiCaller(auth.token)
.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/439618.html
上一篇:移動浮動動作按鈕顫振